LIBOBJS = queue.o route.o waypt.o filter_vecs.o util.o vecs.o mkshort.o \
csv_util.o strptime.o grtcirc.o vmem.o util_crc.o xmlgeneric.o \
uuid.o formspec.o xmltag.o cet.o cet_util.o fatal.o rgbcolors.o \
- inifile.o garmin_fs.o gbsleep.o units.o textfile.o @GBSER@ \
+ inifile.o garmin_fs.o gbsleep.o units.o textfile.o @GBSER@ gbser.o \
$(COLDSYNC) $(GARMIN) $(JEEPS) $(SHAPE) $(FMTS) $(FILTERS)
OBJS = main.o globals.o $(LIBOBJS)
*/
-void *gbser_init(const char *name);
-void gbser_deinit (void *);
-int gbser_read(void *handle, char *ibuf, int sz);
-int gbser_setspeed(void *handle, unsigned speed);
+#ifndef __GBSER_H
+#define __GBSER_H
-#if __WIN32__
-char * fix_win_serial_name(const char *comname);
+#define gbser_OK 0
+#define gbser_NOTHING -1
+#define gbser_TIMEOUT -2
+#define gbser_ERROR -3
+
+#if defined(__WIN32__) || defined(__CYGWIN__)
+#define WINSERIAL 1
+#else
+#define POSIXSERIAL 1
#endif
+
+/* Open a serial port. |port_name| is the (platform specific) name
+ * of the serial device to open. Under WIN32 familiar DOS port names
+ * ('com1:') are translated into the equivalent name required by
+ * WIN32
+ */
+void *gbser_init(const char *port_name);
+
+/* Close a serial port
+ */
+void gbser_deinit(void *handle);
+
+/* Set the serial port speed.
+ */
+int gbser_set_speed(void *handle, unsigned speed);
+
+/* Set the serial port speed, start, parity and stop bits */
+int gbser_set_port(void *handle, unsigned speed,
+ unsigned bits,
+ unsigned parity,
+ unsigned stop);
+
+/* Set the serial port up by parsing the supplied parameter string.
+ * Valid parameter strings look like '4800,8,N,1'. Parsing is case-
+ * insensitive, spaces are allowed around the commas and omitted
+ * trailing fields will default to '8', 'N' and '1'
+ */
+int gbser_setup(void *handle, const char *spec);
+
+/* Return true if there are characters available on the serial port
+ */
+int gbser_avail(void *handle);
+
+/* Read as many bytes as are available without blocking. At most |len|
+ * bytes will be read. Returns the number of bytes read or gbser_ERROR if an
+ * error occurs.
+ */
+int gbser_read(void *handle, void *buf, unsigned len);
+
+/* Read the specified number of bytes. Block until the requested number
+ * of bytes have been read or the timeout (in ms) is exceeded.
+ */
+int gbser_read_wait(void *handle, void *buf, unsigned len, unsigned ms);
+
+/* Read from the serial port until the specified |eol| character is
+ * found. Any character matching |discard| will be discarded. To
+ * read lines terminated by 0x0A0x0D discarding linefeeds use
+ * gbser_read_line(h, buf, len, 1000, 0x0D, 0x0A);
+ */
+int gbser_read_line(void *handle, void *buf,
+ unsigned len, unsigned ms,
+ int eol, int discard);
+
+/* Read a single character from the port, returning immediately if
+ * none are available. TODO: Define return values
+ */
+int gbser_readc(void *handle);
+
+/* Read a single character from the port, waiting up to |ms|
+ * milliseconds for a character to be available.
+ */
+int gbser_readc_wait(void *handle, unsigned ms);
+
+/* Discard any pending input on the serial port.
+ */
+int gbser_flush(void *handle);
+
+/* Write |len| bytes from |buf| to the serial port.
+ */
+int gbser_write(void *handle, const void *buf, unsigned len);
+
+/* Write a null terminated string in |str| to the serial
+ * port.
+ */
+int gbser_print(void *handle, const char *str);
+
+/* Write a single character to the serial port.
+ */
+int gbset_writec(void *handle, int c);
+
+/* Return true if a port name seems to refer to a serial port.
+ * On Windows this tests the filename (against the regex
+ * /^(\\\\\.\\\\)?com\d+:?$/i). On Posix it returns the value of
+ * isatty()
+ */
+int gbser_is_serial(const char *port_name);
+
+/* This isn't part of the above abstraction; it's just a helper for
+ * the other serial modules in the tree.
+ *
+ * Windows does a weird thing with serial ports.
+ * COM ports 1 - 9 are "COM1:" through "COM9:"
+ * The one after that is \\.\\com10 - this function tries to plaster over
+ * that.
+ * It returns a pointer to a staticly allocated buffer and is therefore not
+ * thread safe. The buffer pointed to remains valid only until the next
+ * call to this function.
+ */
+
+const char *fix_win_serial_name_r(const char *comname, char *obuf, size_t len);
+const char *fix_win_serial_name(const char *comname);
+
+#endif /* GBSER_H */
/*
- Serial interface - POSIX layer.
-
+ Serial interface for POSIX tty handling.
+
Copyright (C) 2006 Robert Lipe, robertlipe@usa.net
This program is free software; you can redistribute it and/or modify
#include "defs.h"
#include "gbser.h"
-#include <assert.h>
+#include "gbser_private.h"
+
+#include <sys/time.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
+#include <errno.h>
+
+#include <assert.h>
+#include <stdarg.h>
-#define MYMAGIC 0x91827364
typedef struct {
- struct termios orig_tio;
- struct termios my_tio;
- FILE *fh;
- int fd;
- unsigned long magic;
-} gbser_posix_handle;
-
-static
-speed_t
-mkspeed(unsigned br)
-{
- switch (br) {
- case 1200: return B1200;
- case 2400: return B2400;
- case 4800: return B4800;
- case 9600: return B9600;
- case 19200: return B19200;
+ struct termios old_tio;
+ struct termios new_tio;
+ int fd;
+ unsigned vmin, vtime;
+ unsigned long magic;
+
+ unsigned char inbuf[BUFSIZE];
+ unsigned inbuf_used;
+} gbser_handle;
+
+/* Wrapper to safely cast a void * into a gbser_handle */
+static gbser_handle *gbser__get_handle(void *p) {
+ gbser_handle *h = (gbser_handle *) p;
+ assert(h->magic == MYMAGIC);
+ return h;
+}
+
+static speed_t mkspeed(unsigned br) {
+ switch (br) {
+ case 1200: return B1200;
+ case 2400: return B2400;
+ case 4800: return B4800;
+ case 9600: return B9600;
+ case 19200: return B19200;
#if defined B57600
- case 57600: return B57600;
+ case 57600: return B57600;
#endif
#if defined B115200
- case 115200: return B115200;
+ case 115200: return B115200;
#endif
- default: return B4800;
- }
+ default:
+ fatal("Unsupported serial speed: %d\n", br);
+ return 0; /* keep compiler happy */
+ }
}
-/*
-gbser_istty(void *handle)
-{
- gbser_posix_handle *h = (gbser_posix_handle *) handle;
- assert(h->magic == MYMAGIC);
+typedef struct timeval hp_time;
- return isatty(h->fd);
+static void get_time(hp_time *tv) {
+ gettimeofday(tv, NULL);
}
-*/
-void *
-gbser_init(const char *name)
-{
- gbser_posix_handle *h;
+static double elapsed(hp_time *tv) {
+ hp_time now;
+ double ot = (double) tv->tv_sec * 1000 +
+ (double) tv->tv_usec / 1000;
+ double nt;
+ gettimeofday(&now, NULL);
+ nt = (double) now.tv_sec * 1000 +
+ (double) now.tv_usec / 1000;
+ /*printf("elapsed -> %f\n", nt - ot);*/
+ return nt - ot;
+}
+
+static int set_rx_timeout(gbser_handle *h, unsigned vmin, unsigned vtime) {
+ if (vmin > 255) { vmin = 255; }
+ if (vtime > 255) { vtime = 255; }
+ if (vmin != h->vmin || vtime != h->vtime) {
+ h->vmin = h->new_tio.c_cc[VMIN] = vmin;
+ h->vtime = h->new_tio.c_cc[VTIME] = vtime;
+
+ /*printf("VMIN=%d, VTIME=%d\n", h->vmin, h->vtime);*/
+
+ return tcsetattr(h->fd, TCSANOW, &h->new_tio) ? gbser_ERROR : gbser_OK;
+ } else {
+ return 0;
+ }
+}
+
+/* Open a serial port. |port_name| is the (platform specific) name
+ * of the serial device to open. Under WIN32 familiar DOS port names
+ * ('com1:') are translated into the equivalent name required by
+ * WIN32
+ */
+void *gbser_init(const char *port_name) {
+ gbser_handle *h;
+
+ gbser__db(4, "gbser_init(\"%s\")\n", port_name);
h = xcalloc(sizeof *h, 1);
h->magic = MYMAGIC;
+ h->vmin = h->vtime = 0;
+
+ if (h->fd = open(port_name, O_RDWR | O_NOCTTY), h->fd == -1) {
+ gbser__db(1, "Failed to open port (%s)\n", strerror(errno));
+ goto failed;
+ }
- h->fh = xfopen(name, "rb", "serial layer");
- h->fd = fileno(h->fh);
-// h->fd = open(name, O_RDWR | O_EXCL | O_SYNC);
-
if (!isatty(h->fd)) {
- goto open_fail;
+ gbser__db(1, "%s is not a TTY\n");
+ goto failed;
}
- tcgetattr(h->fd, &h->orig_tio);
-
- h->my_tio = h->orig_tio;
- h->my_tio.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|
- IGNCR|IGNCR|IXON);
- h->my_tio.c_cflag &= ~(CSIZE|PARENB);
- h->my_tio.c_cflag |= CS8;
- h->my_tio.c_oflag = 0;
- h->my_tio.c_lflag = 0;
- h->my_tio.c_iflag = 0;
- h->my_tio.c_cc[VTIME] = 10; /* Time out after one second */
- h->my_tio.c_cc[VMIN] = 255;
+ if (gbser_set_port(h, 4800, 8, 0, 1)) {
+ gbser__db(1, "gbser_set_port() failed\n");
+ goto failed;
+ }
return h;
-open_fail:
- if (h->fh) {
- fclose(h->fh);
+failed:
+ if (h->fd != -1) {
+ close(h->fd);
}
+
xfree(h);
+
return NULL;
}
-void
-gbser_deinit(void *handle)
-{
- gbser_posix_handle *h = (gbser_posix_handle *) handle;
- assert(h->magic == MYMAGIC);
+/* Close a serial port
+ */
+void gbser_deinit(void *handle) {
+ gbser_handle *h = gbser__get_handle(handle);
+
+ tcsetattr(h->fd, TCSAFLUSH, &h->old_tio);
+ close(h->fd);
- tcsetattr(h->fd, TCSAFLUSH, &h->orig_tio);
- fclose(h->fh);
- xfree(handle);
+ xfree(h);
}
-int
-gbser_setspeed(void *handle, unsigned speed)
-{
+int gbser_set_port(void *handle, unsigned speed, unsigned bits, unsigned parity, unsigned stop) {
+ gbser_handle *h = gbser__get_handle(handle);
speed_t s;
- gbser_posix_handle *h = (gbser_posix_handle *) handle;
- assert(h->magic == MYMAGIC);
+
+ static unsigned bit_flags[] = {
+ 0, 0, 0, 0, 0, CS5, CS6, CS7, CS8
+ };
+
+ if (bits < 5 || bits > 8) {
+ fatal("Unsupported bits setting: %d\n", bits);
+ }
+
+ if (parity > 2) {
+ fatal("Unsupported parity setting: %d\n", parity);
+ }
+
+ if (stop < 1 || stop > 2) {
+ fatal("Unsupported stop setting: %d\n", stop);
+ }
s = mkspeed(speed);
- cfsetospeed(&h->my_tio, s);
- cfsetispeed(&h->my_tio, s);
+ /* TODO: We don't /fully/ initialise the port's stat here... */
+
+ tcgetattr(h->fd, &h->old_tio);
+
+ h->new_tio = h->old_tio;
+
+ /* clear bits */
+ cfmakeraw(&h->new_tio);
+
+ h->new_tio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP |
+ INLCR | IGNCR | IXON);
+ h->new_tio.c_cflag &= ~(CSIZE | PARENB | PARODD | CSTOPB);
+
+ /* set data bits, */
+ h->new_tio.c_cflag |= bit_flags[bits];
+
+ /* stop bits and... */
+ if (stop == 2) {
+ h->new_tio.c_cflag |= CSTOPB;
+ }
+
+ /* parity */
+ if (parity != 0) {
+ h->new_tio.c_cflag |= PARENB;
+ if (parity == 1) {
+ h->new_tio.c_cflag |= PARODD;
+ }
+ }
+
+ h->new_tio.c_oflag = 0;
+ h->new_tio.c_lflag = 0;
- return !tcsetattr(h->fd, TCSAFLUSH, &h->my_tio);
+ h->new_tio.c_cc[VMIN] = h->vmin;
+ h->new_tio.c_cc[VTIME] = h->vtime;
+
+ cfsetospeed(&h->new_tio, s);
+ cfsetispeed(&h->new_tio, s);
+
+ return tcsetattr(h->fd, TCSADRAIN, &h->new_tio) ? gbser_ERROR : gbser_OK;
+}
+
+unsigned gbser__read_buffer(void *handle, void **buf, unsigned *len) {
+ gbser_handle *h = gbser__get_handle(handle);
+ unsigned count = *len;
+ unsigned char *cp = *buf;
+ if (count > h->inbuf_used) {
+ count = h->inbuf_used;
+ }
+
+ memcpy(cp, h->inbuf, count);
+ memmove(h->inbuf, h->inbuf + count,
+ h->inbuf_used - count);
+ h->inbuf_used -= count;
+ *len -= count;
+ cp += count;
+ *buf = (void *) cp;
+ return count;
}
-int
-gbser_read(void *handle, char *ibuf, int size)
-{
- gbser_posix_handle *h = (gbser_posix_handle *) handle;
+/* Return when the input buffer contains at least |want| bytes or |*ms|
+ * milliseconds have elapsed. |ms| may be NULL or |*ms| may be zero to
+ * poll the port for available bytes and return immediately. |*ms| will
+ * be updated to indicate the remaining time on exit.
+ * Returns the number of bytes available (>=0) or an error code (<0).
+ */
+int gbser__fill_buffer(void *handle, unsigned want, unsigned *ms) {
+ int rc;
+ gbser_handle *h = gbser__get_handle(handle);
+
+ if (want > BUFSIZE) {
+ want = BUFSIZE;
+ }
- ibuf[0] = 0;
- assert(h->magic == MYMAGIC);
+ /* Already got enough bytes? */
+ if (h->inbuf_used >= want) {
+ return h->inbuf_used;
+ }
+
+ if (NULL == ms || 0 == *ms) {
+ if ((rc = set_rx_timeout(h, 0, 0), rc < 0) ||
+ (rc = read(h->fd, h->inbuf + h->inbuf_used,
+ want - h->inbuf_used), rc < 0)) {
+ return gbser_ERROR;
+ }
+ h->inbuf_used += rc;
+ /*printf("Got %d bytes\n", rc);*/
+ } else {
+ hp_time tv;
+ get_time(&tv);
+ double time_left = *ms;
+
+ for (;;) {
+ fd_set rec;
+ struct timeval t;
+
+ time_left = *ms - elapsed(&tv);
+ if (time_left <= 0 || h->inbuf_used >= want) {
+ break;
+ }
+
+ FD_ZERO(&rec);
+ FD_SET(h->fd, &rec);
+
+ t.tv_sec = (time_t) time_left / 1000;
+ t.tv_usec = (suseconds_t) ((unsigned) time_left % 1000) * 1000;
+
+ if (select(h->fd + 1, &rec, NULL, NULL, &t) < 0) {
+ return gbser_ERROR;
+ }
+
+ time_left = *ms - elapsed(&tv);
+
+ if (FD_ISSET(h->fd, &rec)) {
+ unsigned vmin = 0, vtime = 0;
+ if (time_left >= 100) {
+ vmin = want - h->inbuf_used;
+ vtime = (unsigned) time_left / 100;
+ }
+ if ((rc = set_rx_timeout(h, vmin, vtime), rc < 0) ||
+ (rc = read(h->fd, h->inbuf + h->inbuf_used,
+ want - h->inbuf_used), rc < 0)) {
+ return gbser_ERROR;
+ }
+ h->inbuf_used += rc;
+ /*printf("Got %d bytes\n", rc);*/
+ }
+ }
+ *ms = (time_left < 0) ? 0 : time_left;
+ }
+
+ return h->inbuf_used;
+}
+
+/* Discard any pending input on the serial port.
+ */
+int gbser_flush(void *handle) {
+ gbser_handle *h = gbser__get_handle(handle);
+ h->inbuf_used = 0;
+ if (tcflush(h->fd, TCIFLUSH)) {
+ return gbser_ERROR;
+ }
+
+ return gbser_OK;
+}
+
+/* Write |len| bytes from |buf| to the serial port.
+ */
+int gbser_write(void *handle, const void *buf, unsigned len) {
+ gbser_handle *h = gbser__get_handle(handle);
+ const char *bp = buf;
+ int rc;
+ while (len > 0) {
+ /*printf("write(%d, %p, %d)\n", h->fd, bp, len);*/
+ if (rc = write(h->fd, bp, len), rc < 0) {
+ printf("rc = %d, errno = %d (%s)\n", rc, errno, strerror(errno));
+ return gbser_ERROR;
+ }
+ len -= rc;
+ bp += rc;
+ }
+ return gbser_OK;
+}
+
+/* Return true if a port name seems to refer to a serial port.
+ * On Windows this tests the filename (against the regex
+ * /^(\\\\\.\\\\)?com\d+:?$/i). On Posix it returns the value of
+ * isatty()
+ */
+
+int gbser_is_serial(const char *port_name) {
+ int fd;
+ int is_port = 0;
+
+ if (fd = open(port_name, O_RDWR | O_NOCTTY), fd == -1) {
+ gbser__db(1, "Failed to open port (%s) to check its type\n", strerror(errno));
+ return 0;
+ }
-// n = read(h->fd, ibuf, size);
-// printf("Returning %d\n", n);
-redo:
- fgets(ibuf, size, h->fh);
-// rtrim(ibuf);
-if (strlen(ibuf) == 0)
- goto redo;
- return 1;
+ is_port = isatty(fd);
+
+ close(fd);
+
+ return is_port;
+}
+
+/* This isn't part of the above abstraction; it's just a helper for
+ * the other serial modules in the tree.
+ *
+ * Windows does a weird thing with serial ports.
+ * COM ports 1 - 9 are "COM1:" through "COM9:"
+ * The one after that is \\.\\com10 - this function tries to plaster over
+ * that.
+ * It returns a pointer to a staticly allocated buffer and is therefore not
+ * thread safe. The buffer pointed to remains valid only until the next
+ * call to this function.
+ */
+
+const char *fix_win_serial_name_r(const char *comname, char *obuf, size_t len) {
+ strncpy(obuf, comname, len);
+ return obuf;
+}
+
+static char gb_com_buffer[100];
+
+const char *fix_win_serial_name(const char *comname) {
+ return fix_win_serial_name_r(comname, gb_com_buffer, sizeof(gb_com_buffer));
+}
+
+/* Read from the serial port until the specified |eol| character is
+ * found. Any character matching |discard| will be discarded. To
+ * read lines terminated by 0x0A0x0D discarding linefeeds use
+ * gbser_read_line(h, buf, len, 1000, 0x0D, 0x0A);
+ */
+int gbser_read_line(void *handle, void *buf,
+ unsigned len, unsigned ms,
+ int eol, int discard) {
+ char *bp = buf;
+ unsigned pos = 0;
+ hp_time tv;
+ get_time(&tv);
+ bp[pos] = '\0';
+ for (;;) {
+ unsigned time_left = ms - elapsed(&tv);
+ int c;
+ if (time_left <= 0) {
+ return gbser_TIMEOUT;
+ }
+ c = gbser_readc_wait(handle, time_left);
+ if (c == gbser_ERROR) {
+ return c;
+ } else if (c == eol) {
+ return gbser_OK;
+ }
+ if (c != gbser_NOTHING && c != discard && pos < len - 1) {
+ bp[pos++] = c;
+ bp[pos] = '\0';
+ }
+ }
}
/*
Serial interface - Windows layer.
-
+
Copyright (C) 2006 Robert Lipe, robertlipe@usa.net
This program is free software; you can redistribute it and/or modify
#include "defs.h"
#include "gbser.h"
+#include "gbser_private.h"
+
#include <windows.h>
#include <setupapi.h>
-typedef struct gbser_win_handle {
- HANDLE comport;
-} gbser_win_handle;
+#include <assert.h>
+#include <stdarg.h>
-#define xCloseHandle(a) if (a) { CloseHandle(a); } a = NULL;
+typedef struct {
+ HANDLE comport;
+ DWORD timeout;
+ unsigned long magic;
-void *
-gbser_init(const char *portname)
-{
-// DCB tio;
- COMMTIMEOUTS timeout;
- HANDLE comport;
-// char *xname= xstrdup("\\\\.\\\\");
- char *xname = fix_win_serial_name(portname);
- gbser_win_handle* handle = xcalloc(1, sizeof(*handle));;
-
-// /* Amazingly, windows will fail the open below unless we
-// * prepend \\.\ to the name. It also then fails the open
-// * unless we strip the colon from the name. Aaaaargh!
-// */
-// xname = xstrappend(xname, portname);
-// if (xname[strlen(xname)-1] == ':')
-// xname[strlen(xname)-1] = 0;
-// xCloseHandle(comport);
-
- comport = CreateFile(xname, GENERIC_READ|GENERIC_WRITE,
- 0, NULL, OPEN_EXISTING, 0, NULL);
+ unsigned char inbuf[BUFSIZE];
+ unsigned inbuf_used;
+} gbser_handle;
- if (comport == INVALID_HANDLE_VALUE) {
- return NULL;
- }
- handle->comport = comport;
+#define DEV_PREFIX "\\\\.\\\\"
-#if 0
- tio.DCBlength = sizeof(DCB);
- GetCommState (comport, &tio);
-// tio.BaudRate = mkspeed(bitrate);
- {
- extern int mkspeed(int);
- tio.BaudRate = mkspeed(4800);
- }
- tio.fBinary = TRUE;
- tio.fParity = TRUE;
- tio.fOutxCtsFlow = FALSE;
- tio.fOutxDsrFlow = FALSE;
- tio.fDtrControl = DTR_CONTROL_ENABLE;
- tio.fDsrSensitivity = FALSE;
- tio.fTXContinueOnXoff = TRUE;
- tio.fOutX = FALSE;
- tio.fInX = FALSE;
- tio.fErrorChar = FALSE;
- tio.fNull = FALSE;
- tio.fRtsControl = RTS_CONTROL_ENABLE;
- tio.fAbortOnError = FALSE;
- tio.ByteSize = 8;
- tio.Parity = NOPARITY;
- tio.StopBits = ONESTOPBIT;
-
- if (!SetCommState (comport, &tio)) {
- /*
- * Probably not a com port. Let caller try it as a file.
- */
-
- return NULL;
- }
-#else
- gbser_setspeed(handle, 4800);
-#endif
-
- GetCommTimeouts (comport, &timeout);
- /* We basically do single character reads and simulate line input
- * mode, so these values are kind of fictional.
- */
- timeout.ReadIntervalTimeout = 1000;
- timeout.ReadTotalTimeoutMultiplier = 1000;
- timeout.ReadTotalTimeoutConstant = 1000;
- timeout.WriteTotalTimeoutMultiplier = 1000;
- timeout.WriteTotalTimeoutConstant = 1000;
- if (!SetCommTimeouts (comport, &timeout)) {
- xCloseHandle (comport);
- fatal("SetCommTimeouts failed.\n");
- }
- return handle;
+/* Wrapper to safely cast a void * into a gbser_handle */
+static gbser_handle *gbser__get_handle(void *p) {
+ gbser_handle *h = (gbser_handle *) p;
+ assert(h->magic == MYMAGIC);
+ return h;
}
-/*
- * Returns 1 on success, 0 on errro.
- */
-int
-gbser_setspeed(void *handle, unsigned speed)
-{
- extern int mkspeed(int); /* From magproto.c */
- gbser_win_handle *h = (gbser_win_handle *) handle;
- DCB tio;
-
- tio.DCBlength = sizeof(DCB);
- GetCommState(h->comport, &tio);
-
- tio.BaudRate = mkspeed(speed);
- tio.fBinary = TRUE;
- tio.fParity = TRUE;
- tio.fOutxCtsFlow = FALSE;
- tio.fOutxDsrFlow = FALSE;
- tio.fDtrControl = DTR_CONTROL_ENABLE;
- tio.fDsrSensitivity = FALSE;
- tio.fTXContinueOnXoff = TRUE;
- tio.fOutX = FALSE;
- tio.fInX = FALSE;
- tio.fErrorChar = FALSE;
- tio.fNull = FALSE;
- tio.fRtsControl = RTS_CONTROL_ENABLE;
- tio.fAbortOnError = FALSE;
- tio.ByteSize = 8;
- tio.Parity = NOPARITY;
- tio.StopBits = ONESTOPBIT;
-
- if (!SetCommState (h->comport, &tio)) {
- /*
- * Probably not a com port. Let caller try it as a file.
- */
-
- return 0;
+static DWORD mkspeed(unsigned br) {
+ switch (br) {
+ case 1200: return CBR_1200;
+ case 2400: return CBR_2400;
+ case 4800: return CBR_4800;
+ case 9600: return CBR_9600;
+ case 19200: return CBR_19200;
+ case 57600: return CBR_57600;
+ case 115200: return CBR_115200;
+ default:
+ fatal("Unsupported serial speed: %d\n", br);
+ return 0; /* keep compiler happy */
}
- return 1;
}
-int
-gbser_read(void *handle, char *ibuf, int size)
-{
- gbser_win_handle *h = (gbser_win_handle *) handle;
- int i = 0;
- DWORD cnt;
-
- ibuf[0]='0';
- for(;i < size;i++) {
- if (ReadFile (h->comport, &ibuf[i], 1, &cnt, NULL) != TRUE)
- break;
- if (cnt < 1)
- return 0;
- if (ibuf[i] == '\n')
- break;
- }
+typedef LARGE_INTEGER hp_time;
- ibuf[i] = 0;
- return 1;
+static void get_time(hp_time *tv) {
+ QueryPerformanceCounter(tv);
}
-void
-gbser_deinit(void *handle)
-{
- gbser_win_handle *h = (gbser_win_handle *) handle;
- xfree(h);
-}
+static double elapsed(hp_time *tv) {
+ hp_time now;
+ LARGE_INTEGER tps;
+ QueryPerformanceFrequency(&tps);
+ QueryPerformanceCounter(&now);
+ return ((double) (now.QuadPart - tv->QuadPart) /
+ (double) tps.QuadPart) * 1000;
+}
+static int set_rx_timeout(gbser_handle *h, DWORD timeout) {
+ if (timeout != h->timeout) {
+ COMMTIMEOUTS to;
-/*
- * This isn't part of the above abstraction; it's just a helper for
+ if (!GetCommTimeouts(h->comport, &to)) {
+ return gbser_ERROR;
+ }
+
+ to.ReadIntervalTimeout = timeout;
+ to.ReadTotalTimeoutMultiplier = 0;
+ to.ReadTotalTimeoutConstant = timeout;
+ to.WriteTotalTimeoutMultiplier = 0;
+ to.WriteTotalTimeoutConstant = 0;
+
+ if (!SetCommTimeouts(h->comport, &to)) {
+ return gbser_ERROR;
+ } else {
+ h->timeout = timeout;
+ return gbser_OK;
+ }
+ } else {
+ return gbser_OK;
+ }
+}
+
+/* This isn't part of the above abstraction; it's just a helper for
* the other serial modules in the tree.
*
* Windows does a weird thing with serial ports.
* thread safe. The buffer pointed to remains valid only until the next
* call to this function.
*/
-static char gb_com_buffer[100];
-char *
-fix_win_serial_name(const char *comname)
-{
- /* If in the form 'COMx:', use it in place */
- if ((strlen(comname) == 5) && (comname[4] == ':')) {
- strcpy(gb_com_buffer, comname);
+const char *fix_win_serial_name_r(const char *comname, char *obuf, size_t len) {
+ if (!gbser_is_serial(comname) ||
+ ((strlen(comname) == 5) && (comname[4] == ':'))) {
+ strncpy(obuf, comname, len);
} else {
- snprintf(gb_com_buffer, sizeof(gb_com_buffer),
- "\\\\.\\\\%s", comname);
- if (gb_com_buffer[strlen(gb_com_buffer) - 1 ] == ':') {
- gb_com_buffer[strlen(gb_com_buffer) - 1] = 0;
+ size_t l;
+ snprintf(obuf, len, DEV_PREFIX "%s", comname);
+ l = strlen(obuf);
+ if (obuf[l - 1] == ':') {
+ obuf[l - 1] = '\0';
}
}
- return gb_com_buffer;
+
+ return obuf;
+}
+
+static char gb_com_buffer[100];
+
+const char *fix_win_serial_name(const char *comname) {
+ return fix_win_serial_name_r(comname, gb_com_buffer, sizeof(gb_com_buffer));
+}
+
+/* Open a serial port. |port_name| is the (platform specific) name
+ * of the serial device to open. Under WIN32 familiar DOS port names
+ * ('com1:') are translated into the equivalent name required by
+ * WIN32
+ */
+void *gbser_init(const char *port_name) {
+ HANDLE comport;
+ gbser_handle* h = xcalloc(1, sizeof(*h));
+ const char *xname = fix_win_serial_name(port_name);
+
+ gbser__db(2, "Translated port name: \"%s\"\n", xname);
+
+ h->magic = MYMAGIC;
+
+ comport = CreateFile(xname, GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (comport == INVALID_HANDLE_VALUE) {
+ goto failed;
+ }
+
+ h->comport = comport;
+ h->timeout = 1;
+
+ if (gbser_set_port(h, 4800, 8, 0, 1) || set_rx_timeout(h, 0)) {
+ goto failed;
+ }
+
+ return h;
+
+failed:
+ if (comport) { CloseHandle(h->comport); }
+ xfree(h);
+
+ return NULL;
+}
+
+/* Close a serial port
+ */
+void gbser_deinit(void *handle) {
+ gbser_handle *h = gbser__get_handle(handle);
+
+ CloseHandle(h->comport);
+
+ xfree(h);
+}
+
+int gbser_set_port(void *handle, unsigned speed, unsigned bits, unsigned parity, unsigned stop) {
+ gbser_handle *h = gbser__get_handle(handle);
+ DCB tio;
+
+ if (bits < 5 || bits > 8) {
+ fatal("Unsupported bits setting: %d\n", bits);
+ }
+
+ if (parity > 2) {
+ fatal("Unsupported parity setting: %d\n", parity);
+ }
+
+ if (stop < 1 || stop > 2) {
+ fatal("Unsupported stop setting: %d\n", stop);
+ }
+
+ tio.DCBlength = sizeof(DCB);
+ GetCommState(h->comport, &tio);
+
+ tio.BaudRate = mkspeed(speed);
+ tio.fBinary = TRUE;
+ tio.fParity = TRUE;
+ tio.fOutxCtsFlow = FALSE;
+ tio.fOutxDsrFlow = FALSE;
+ tio.fDtrControl = DTR_CONTROL_ENABLE;
+ tio.fDsrSensitivity = FALSE;
+ tio.fTXContinueOnXoff = TRUE;
+ tio.fOutX = FALSE;
+ tio.fInX = FALSE;
+ tio.fErrorChar = FALSE;
+ tio.fNull = FALSE;
+ tio.fRtsControl = RTS_CONTROL_ENABLE;
+ tio.fAbortOnError = FALSE;
+ tio.ByteSize = bits;
+ tio.Parity = parity == 0 ? NOPARITY :
+ (parity == 1 ? ODDPARITY : EVENPARITY);
+ tio.StopBits = stop == 1 ? ONESTOPBIT : TWOSTOPBITS;
+
+ if (!SetCommState(h->comport, &tio)) {
+ return gbser_ERROR;
+ }
+ return gbser_OK;
+}
+
+unsigned gbser__read_buffer(void *handle, void **buf, unsigned *len) {
+ gbser_handle *h = gbser__get_handle(handle);
+ unsigned count = *len;
+ unsigned char *cp = *buf;
+ if (count > h->inbuf_used) {
+ count = h->inbuf_used;
+ }
+
+ memcpy(cp, h->inbuf, count);
+ memmove(h->inbuf, h->inbuf + count,
+ h->inbuf_used - count);
+ h->inbuf_used -= count;
+ *len -= count;
+ cp += count;
+ *buf = (void *) cp;
+ return count;
+}
+
+/* Return when the input buffer contains at least |want| bytes or |*ms|
+ * milliseconds have elapsed. |ms| may be NULL or |*ms| may be zero to
+ * poll the port for available bytes and return immediately. |*ms| will
+ * be updated to indicate the remaining time on exit.
+ * Returns the number of bytes available (>=0) or an error code (<0).
+ */
+int gbser__fill_buffer(void *handle, unsigned want, unsigned *ms) {
+ int rc;
+ gbser_handle *h = gbser__get_handle(handle);
+
+ if (want > BUFSIZE) {
+ want = BUFSIZE;
+ }
+
+ /* Already got enough bytes? */
+ if (h->inbuf_used >= want) {
+ return h->inbuf_used;
+ }
+
+ if (NULL == ms || 0 == *ms) {
+ DWORD err, nread;
+ COMSTAT stat;
+ ClearCommError(h->comport, &err, &stat);
+ if (stat.cbInQue > 0) {
+ DWORD count = want - h->inbuf_used;
+ if (count > stat.cbInQue) {
+ count = stat.cbInQue;
+ }
+ if (rc = set_rx_timeout(h, 1), rc) {
+ return rc;
+ }
+ if (!ReadFile(h->comport, h->inbuf + h->inbuf_used,
+ count, &nread, NULL)) {
+ err = GetLastError();
+ if (err != ERROR_COUNTER_TIMEOUT && err != ERROR_TIMEOUT) {
+ return gbser_ERROR;
+ }
+ }
+ h->inbuf_used += nread;
+ }
+ } else {
+ hp_time tv;
+ double time_left;
+ DWORD err, nread;
+ get_time(&tv);
+ if (rc = set_rx_timeout(h, *ms), rc) {
+ return rc;
+ }
+ if (!ReadFile(h->comport, h->inbuf + h->inbuf_used,
+ want - h->inbuf_used,
+ &nread, NULL)) {
+ err = GetLastError();
+ if (err != ERROR_COUNTER_TIMEOUT && err != ERROR_TIMEOUT) {
+ return gbser_ERROR;
+ }
+ }
+ h->inbuf_used += nread;
+ time_left = *ms - elapsed(&tv);
+ *ms = time_left < 0 ? 0 : (unsigned) time_left;
+ }
+
+ return h->inbuf_used;
+}
+
+/* Discard any pending input on the serial port.
+ */
+int gbser_flush(void *handle) {
+ gbser_handle *h = gbser__get_handle(handle);
+ h->inbuf_used = 0;
+ if (!PurgeComm(h->comport, PURGE_RXCLEAR)) {
+ return gbser_ERROR;
+ }
+ return gbser_OK;
+}
+
+/* Write |len| bytes from |buf| to the serial port.
+ */
+int gbser_write(void *handle, const void *buf, unsigned len) {
+ gbser_handle *h = gbser__get_handle(handle);
+ DWORD nwritten;
+ const char *bp = buf;
+ /* Not sure we need to spin here - but this'll work even if we don't */
+ while (len > 0) {
+ if (!WriteFile(h->comport, bp, len, &nwritten, NULL)) {
+ return gbser_ERROR;
+ }
+ len -= nwritten;
+ bp += nwritten;
+ }
+ return gbser_OK;
+}
+
+/* Return true if a port name seems to refer to a serial port.
+ * On Windows this tests the filename (against the regex
+ * /^(\\\\\.\\\\)?com\d+:?$/i). On Posix it returns the value of
+ * isatty()
+ */
+
+int gbser_is_serial(const char *port_name) {
+ const char *pfx = DEV_PREFIX;
+ size_t pfx_l = strlen(pfx);
+ const char *com = "COM";
+ size_t com_l = strlen(com);
+ unsigned digits;
+
+ /* Skip any prefix */
+ if (memcmp(port_name, pfx, pfx_l) == 0) {
+ port_name += pfx_l;
+ }
+
+ if (case_ignore_strncmp(port_name, com, com_l) != 0) {
+ return 0;
+ }
+
+ port_name += com_l;
+ for (digits = 0; isdigit(*port_name); port_name++, digits++) {
+ /* do nothing */
+ }
+
+ if (digits == 0) {
+ return 0;
+ }
+
+ if (*port_name == ':') {
+ port_name++;
+ }
+
+ if (*port_name != '\0') {
+ return 0;
+ }
+
+ /* Success! */
+ return 1;
+}
+
+/* Read from the serial port until the specified |eol| character is
+ * found. Any character matching |discard| will be discarded. To
+ * read lines terminated by 0x0A0x0D discarding linefeeds use
+ * gbser_read_line(h, buf, len, 1000, 0x0D, 0x0A);
+ */
+int gbser_read_line(void *handle, void *buf,
+ unsigned len, unsigned ms,
+ int eol, int discard) {
+ char *bp = buf;
+ unsigned pos = 0;
+ hp_time tv;
+ get_time(&tv);
+ bp[pos] = '\0';
+ for (;;) {
+ unsigned time_left = ms - elapsed(&tv);
+ int c;
+ if (time_left <= 0) {
+ return gbser_TIMEOUT;
+ }
+ c = gbser_readc_wait(handle, time_left);
+ if (c == gbser_ERROR) {
+ return c;
+ } else if (c == eol) {
+ return gbser_OK;
+ }
+ if (c != gbser_NOTHING && c != discard && pos < len - 1) {
+ bp[pos++] = c;
+ bp[pos] = '\0';
+ }
+ }
}
char icon[3] = {0};
waypoint *wpt_tmp;
textfile_t *tin;
-
- tin = textfile_init(file_in);
/*
* Make sure that all waypoints in single read have same
* timestamp.
*/
time_t now = current_time();
+
+ tin = textfile_init(file_in);
while ((ibuf = textfile_read(tin))) {
/* A sharp in column zero or an blank line is a comment */
DCB tio;
COMMTIMEOUTS timeout;
HANDLE comport;
- char *xname = fix_win_serial_name(port);
+ const char *xname = fix_win_serial_name(port);
win_serial_data *wsd = xcalloc(sizeof (win_serial_data), 1);
*dh = (gpsdevh*) wsd;
#define debug_serial (global_opts.debug_level > 1)
-static char * termread(char *ibuf, int size);
+static char *termread(char *ibuf, int size);
static void termwrite(char *obuf, int size);
static void mag_readmsg(gpsdata_type objective);
static void mag_handon(void);
static queue rte_wpt_tmp; /* temporary PGMNWPL msgs for routes */
-static FILE *magfile_in;
-static FILE *magfile_out;
-static int magfd;
+static FILE *magfile_h;
static mag_rxstate magrxstate;
static int mag_error;
static unsigned int last_rx_csum;
ignore_unable = 0;
return;
}
- if (IS_TKN("$PMGNCMD,END") || (is_file && (feof(magfile_in)))) {
+ if (IS_TKN("$PMGNCMD,END") || (is_file && (feof(magfile_h)))) {
found_done = 1;
return;
}
mag_writeack(isum);
}
-/*
- * termio on Cygwin is apparently broken, so we revert to Windows serial.
- */
-#if defined (__WIN32__) || defined (__CYGWIN__)
-
-#include <windows.h>
-
-DWORD
-mkspeed(bitrate)
-{
- switch (bitrate) {
- case 1200: return CBR_1200;
- case 2400: return CBR_2400;
- case 4800: return CBR_4800;
- case 9600: return CBR_9600;
- case 19200: return CBR_19200;
- case 57600: return CBR_57600;
- case 115200: return CBR_115200;
- default: return CBR_4800;
- }
-}
-
-HANDLE comport = NULL;
-
-#define xCloseHandle(a) if (a) { CloseHandle(a); } a = NULL;
-
-static
-int
-terminit(const char *portname, int create_ok)
-{
- DCB tio;
- char *xname = fix_win_serial_name(portname);
- COMMTIMEOUTS timeout;
-
- is_file = 0;
+static void *serial_handle = NULL;
- xCloseHandle(comport);
-
- comport = CreateFile(xname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
- OPEN_EXISTING, 0, NULL);
- if (comport == INVALID_HANDLE_VALUE) {
- goto try_as_file;
- }
- tio.DCBlength = sizeof(DCB);
- GetCommState (comport, &tio);
- tio.BaudRate = mkspeed(bitrate);
- tio.fBinary = TRUE;
- tio.fParity = TRUE;
- tio.fOutxCtsFlow = FALSE;
- tio.fOutxDsrFlow = FALSE;
- tio.fDtrControl = DTR_CONTROL_ENABLE;
- tio.fDsrSensitivity = FALSE;
- tio.fTXContinueOnXoff = TRUE;
- tio.fOutX = FALSE;
- tio.fInX = FALSE;
- tio.fErrorChar = FALSE;
- tio.fNull = FALSE;
- tio.fRtsControl = RTS_CONTROL_ENABLE;
- tio.fAbortOnError = FALSE;
- tio.ByteSize = 8;
- tio.Parity = NOPARITY;
- tio.StopBits = ONESTOPBIT;
-
- if (!SetCommState (comport, &tio)) {
- xCloseHandle(comport);
-
- /*
- * Probably not a com port. Try it as a file.
- */
-try_as_file:
- magfile_in = xfopen(portname, create_ok ? "w+b" : "rb", MYNAME);
+static int terminit(const char *portname, int create_ok) {
+ if (gbser_is_serial(portname)) {
+ if (serial_handle = gbser_init(portname), NULL != serial_handle) {
+ int rc;
+ if (rc = gbser_set_port(serial_handle, bitrate, 8, 0, 1), gbser_OK != rc) {
+ fatal(MYNAME ": Can't configure port\n");
+ }
+ }
+ is_file = 0;
+ return 1;
+ } else {
+ /* Does this check for an error? */
+ magfile_h = xfopen(portname, create_ok ? "w+b" : "rb", MYNAME);
is_file = 1;
icon_mapping = map330_icon_table;
mag_cleanse = m330_cleanse;
got_version = 1;
return 0;
}
-
- GetCommTimeouts (comport, &timeout);
- /* We basically do single character reads and simulate line input
- * mode, so these values are kind of fictional.
- */
- timeout.ReadIntervalTimeout = 1000;
- timeout.ReadTotalTimeoutMultiplier = 1000;
- timeout.ReadTotalTimeoutConstant = 1000;
- timeout.WriteTotalTimeoutMultiplier = 1000;
- timeout.WriteTotalTimeoutConstant = 1000;
- if (!SetCommTimeouts (comport, &timeout)) {
- xCloseHandle (comport);
- fatal(MYNAME ": set timeouts\n");
- }
- return 1;
}
-static char *
-termread(char *ibuf, int size)
-{
- int i=0;
- DWORD cnt;
-
+static char *termread(char *ibuf, int size) {
if (is_file) {
- return fgets(ibuf, size, magfile_in);
- }
-
- ibuf[i]='a';
- for(;i < size;i++) {
- if (ReadFile (comport, &ibuf[i], 1, &cnt, NULL) != TRUE)
- break;
- if (cnt < 1)
- return NULL;
- if (ibuf[i] == '\n')
- break;
+ return fgets(ibuf, size, magfile_h);
+ } else {
+ int rc = gbser_read_line(serial_handle, ibuf, size, 2000, '\x0a', '\x0d');
+ if (rc != gbser_OK) {
+ fatal(MYNAME ": Read error\n");
+ }
+ return ibuf;
}
- ibuf[i] = 0;
- return ibuf;
}
-static void
-termwrite(char *obuf, int size)
-{
- DWORD len;
-
+static void termwrite(char *obuf, int size) {
if (is_file) {
- fwrite(obuf, size, 1, magfile_out);
- return;
- }
- WriteFile (comport, obuf, size, &len, NULL);
- if ((int) len != size) {
- fatal(MYNAME ":. Wrote %d of %d bytes.\n", len, size);
- }
-}
-
-static
-void
-termdeinit()
-{
- xCloseHandle(comport);
-}
-
-#else
-
-#include <termios.h>
-#include <unistd.h>
-
-speed_t
-mkspeed(unsigned br)
-{
- switch (br) {
- case 1200: return B1200;
- case 2400: return B2400;
- case 4800: return B4800;
- case 9600: return B9600;
- case 19200: return B19200;
-#if defined B57600
- case 57600: return B57600;
-#endif
-#if defined B115200
- case 115200: return B115200;
-#endif
- default: return B4800;
+ size_t nw;
+ if (nw = fwrite(obuf, 1, size, magfile_h), nw < (size_t) size) {
+ fatal(MYNAME ": Write error");
+ }
+ } else {
+ int rc;
+ if (rc = gbser_write(serial_handle, obuf, size), rc < 0) {
+ fatal(MYNAME ": Write error");
+ }
}
}
-
-static struct termios orig_tio;
-static void
-terminit(const char *portname, int create_ok)
-{
- struct termios new_tio;
-
- magfile_in = xfopen(portname, "rb", MYNAME);
-
- is_file = (0 == strcmp(portname,"-")) || !isatty(fileno(magfile_in)) || explorist;
+static void termdeinit() {
if (is_file) {
- icon_mapping = map330_icon_table;
- mag_cleanse = m330_cleanse;
- got_version = 1;
- return;
- }
-
- magfile_out = xfopen(portname, "w+b", MYNAME);
- magfd = fileno(magfile_in);
-
- tcgetattr(magfd, &orig_tio);
- new_tio = orig_tio;
- new_tio.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|
- IGNCR|ICRNL|IXON);
- new_tio.c_oflag &= ~OPOST;
- new_tio.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
- new_tio.c_cflag &= ~(CSIZE|PARENB);
- new_tio.c_cflag |= CS8;
- new_tio.c_cc[VTIME] = 10;
- new_tio.c_cc[VMIN] = 0;
-
- cfsetospeed(&new_tio, mkspeed(bitrate));
- cfsetispeed(&new_tio, mkspeed(bitrate));
- tcsetattr(magfd, TCSAFLUSH, &new_tio);
-}
-
-static void
-termdeinit()
-{
- if (!is_file) {
- tcsetattr(magfd, TCSANOW, &orig_tio);
+ fclose(magfile_h);
+ magfile_h = NULL;
+ } else {
+ gbser_deinit(serial_handle);
+ serial_handle = NULL;
}
}
-static char *
-termread(char *ibuf, int size)
-{
- return fgets(ibuf, size, magfile_in);
-}
-
-static void
-termwrite(char *obuf, int size)
-{
- fwrite(obuf, size, 1, magfile_out);
-}
-#endif
-
/*
* Arg tables are doubled up so that -? can output appropriate help
*/
wptcmtcnt_max = MAXCMTCT ;
}
-#if __WIN32__
- if (!terminit(portname, 1)) {
- is_file = 1;
- }
-#else
- magfile_out = xfopen(portname, "w+b", MYNAME);
- is_file = (0 == strcmp(portname,"-")) || !isatty(fileno(magfile_out)) || explorist;
-#endif
+ terminit(portname, 1);
if (!mkshort_handle) {
mkshort_handle = mkshort_new_handle();
}
- if (is_file) {
- magfile_out = xfopen(portname, "w+b", MYNAME);
- icon_mapping = map330_icon_table;
- mag_cleanse = m330_cleanse;
- got_version = 1;
- } else {
- /*
- * This is a serial device. The line has to be open for
- * reading and writing, so we let rd_init do the dirty work.
- */
- if (magfile_out) {
- fclose(magfile_out);
- }
-#if __WIN32__
- if (comport) {
- xCloseHandle(comport);
- }
-#endif
- mag_rd_init(portname);
- }
+
QUEUE_INIT(&rte_wpt_tmp);
}
{
mag_handoff();
termdeinit();
- if(magfile_in)
- fclose(magfile_in);
- magfile_in = NULL;
if(mkshort_handle)
mkshort_del_handle(&mkshort_handle);
mag_read(void)
{
found_done = 0;
-
if (global_opts.masked_objective & TRKDATAMASK) {
+ magrxstate = mrs_handoff;
if (!is_file)
mag_writemsg("PMGNCMD,TRACK,2");
}
if (global_opts.masked_objective & WPTDATAMASK) {
+ magrxstate = mrs_handoff;
if (!is_file)
mag_writemsg("PMGNCMD,WAYPOINT");
}
if (global_opts.masked_objective & RTEDATAMASK) {
+ magrxstate = mrs_handoff;
if (!is_file) {
/*
* serial routes require waypoint & routes
-Microsoft Visual Studio Solution File, Format Version 8.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GPSBabel", "GPSBabel.vcproj", "{EB2609DB-5800-45B2-BCB2-06D72F389DCA}"
- ProjectSection(ProjectDependencies) = postProject
- EndProjectSection
-EndProject
-Global
- GlobalSection(SolutionConfiguration) = preSolution
- Debug = Debug
- Release = Release
- EndGlobalSection
- GlobalSection(ProjectConfiguration) = postSolution
- {EB2609DB-5800-45B2-BCB2-06D72F389DCA}.Debug.ActiveCfg = Debug|Win32
- {EB2609DB-5800-45B2-BCB2-06D72F389DCA}.Debug.Build.0 = Debug|Win32
- {EB2609DB-5800-45B2-BCB2-06D72F389DCA}.Release.ActiveCfg = Release|Win32
- {EB2609DB-5800-45B2-BCB2-06D72F389DCA}.Release.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- EndGlobalSection
- GlobalSection(ExtensibilityAddIns) = postSolution
- EndGlobalSection
-EndGlobal
+\r
+Microsoft Visual Studio Solution File, Format Version 9.00\r
+# Visual C++ Express 2005\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GPSBabel", "GPSBabel.vcproj", "{D81B30A1-C560-42BC-AE80-257FDDD484D8}"\r
+EndProject\r
+Global\r
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+ Debug|Win32 = Debug|Win32\r
+ Release|Win32 = Release|Win32\r
+ EndGlobalSection\r
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+ {D81B30A1-C560-42BC-AE80-257FDDD484D8}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {D81B30A1-C560-42BC-AE80-257FDDD484D8}.Debug|Win32.Build.0 = Debug|Win32\r
+ {D81B30A1-C560-42BC-AE80-257FDDD484D8}.Release|Win32.ActiveCfg = Release|Win32\r
+ {D81B30A1-C560-42BC-AE80-257FDDD484D8}.Release|Win32.Build.0 = Release|Win32\r
+ EndGlobalSection\r
+ GlobalSection(SolutionProperties) = preSolution\r
+ HideSolutionNode = FALSE\r
+ EndGlobalSection\r
+EndGlobal\r
ProjectType="Visual C++"\r
Version="8.00"\r
Name="GPSBabel"\r
- ProjectGUID="{EB2609DB-5800-45B2-BCB2-06D72F389DCA}"\r
+ ProjectGUID="{D81B30A1-C560-42BC-AE80-257FDDD484D8}"\r
>\r
<Platforms>\r
<Platform\r
Optimization="0"\r
InlineFunctionExpansion="1"\r
AdditionalIncludeDirectories="expat,..\coldsync;."\r
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;__WIN32__;VERSION=\"1.2.1_beta01072004_msvc\";_CRT_SECURE_NO_DEPRECATE"\r
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;__WIN32__;VERSION=\"1.3.0\";_CRT_SECURE_NO_DEPRECATE"\r
StringPooling="true"\r
RuntimeLibrary="0"\r
EnableFunctionLevelLinking="true"\r
Name="VCCLCompilerTool"\r
Optimization="0"\r
AdditionalIncludeDirectories="expat,..\coldsync;."\r
- PreprocessorDefinitions="WIN32;__WIN32__;_DEBUG;_CONSOLE;VERSION=\"1.2.1_beta01072004_msvc\";_CRT_SECURE_NO_DEPRECATE"\r
+ PreprocessorDefinitions="WIN32;__WIN32__;_DEBUG;_CONSOLE;VERSION=\"1.3.0\";_CRT_SECURE_NO_DEPRECATE"\r
BasicRuntimeChecks="3"\r
RuntimeLibrary="1"\r
UsePrecompiledHeader="0"\r
RelativePath="..\garmin_tables.c"\r
>\r
</File>\r
+ <File\r
+ RelativePath="..\gbser.c"\r
+ >\r
+ </File>\r
<File\r
RelativePath="..\gbser_win.c"\r
>\r
/>\r
</FileConfiguration>\r
</File>\r
+ <File\r
+ RelativePath="..\textfile.c"\r
+ >\r
+ </File>\r
<File\r
RelativePath="..\tiger.c"\r
>\r
RelativePath="..\garmin_tables.h"\r
>\r
</File>\r
+ <File\r
+ RelativePath="..\gbser.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\gbser_private.h"\r
+ >\r
+ </File>\r
<File\r
RelativePath="..\grtcirc.h"\r
>\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<gpx
+ version="1.0"
+creator="GPSBabel - http://www.gpsbabel.org"
+xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+xmlns="http://www.topografix.com/GPX/1/0"
+xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
+<bounds minlat="54.785117200" minlon ="-2.345095800" maxlat="54.787984800" maxlon="-2.342500800" />
+<trk>
+<trkseg>
+<trkpt lat="54.786918600" lon="-2.344296200">
+ <speed>0.556136</speed>
+ <name>WP0001</name>
+</trkpt>
+<trkpt lat="54.786917800" lon="-2.344315400">
+ <course>94.133018</course>
+ <speed>0.247108</speed>
+ <name>WP0002</name>
+</trkpt>
+<trkpt lat="54.786918500" lon="-2.344317400">
+ <course>58.742805</course>
+ <speed>0.026882</speed>
+ <name>WP0003</name>
+</trkpt>
+<trkpt lat="54.786921300" lon="-2.344313000">
+ <speed>0.085008</speed>
+ <name>WP0004</name>
+</trkpt>
+<trkpt lat="54.786923900" lon="-2.344310300">
+ <speed>0.065847</speed>
+ <name>WP0005</name>
+</trkpt>
+<trkpt lat="54.786926200" lon="-2.344311600">
+ <course>18.051563</course>
+ <speed>0.050291</speed>
+ <name>WP0006</name>
+</trkpt>
+<trkpt lat="54.786925900" lon="-2.344315900">
+ <course>96.898911</course>
+ <speed>0.053764</speed>
+ <name>WP0007</name>
+</trkpt>
+<trkpt lat="54.786924000" lon="-2.344320400">
+ <course>126.213005</course>
+ <speed>0.071123</speed>
+ <name>WP0008</name>
+</trkpt>
+<trkpt lat="54.786922100" lon="-2.344322900">
+ <course>142.812088</course>
+ <speed>0.050291</speed>
+ <name>WP0009</name>
+</trkpt>
+<trkpt lat="54.786919800" lon="-2.344325500">
+ <course>146.902481</course>
+ <speed>0.060110</speed>
+ <name>WP0010</name>
+</trkpt>
+<trkpt lat="54.786917100" lon="-2.344328300">
+ <course>149.121628</course>
+ <speed>0.068536</speed>
+ <name>WP0011</name>
+</trkpt>
+<trkpt lat="54.786913900" lon="-2.344332500">
+ <course>142.881119</course>
+ <speed>0.087107</speed>
+ <name>WP0012</name>
+</trkpt>
+<trkpt lat="54.786910500" lon="-2.344337100">
+ <course>142.041077</course>
+ <speed>0.095042</speed>
+ <name>WP0013</name>
+</trkpt>
+<trkpt lat="54.786907000" lon="-2.344341500">
+ <course>144.061920</course>
+ <speed>0.095042</speed>
+ <name>WP0014</name>
+</trkpt>
+<trkpt lat="54.786904000" lon="-2.344345500">
+ <course>142.445999</course>
+ <speed>0.082855</speed>
+ <name>WP0015</name>
+</trkpt>
+<trkpt lat="54.786901500" lon="-2.344348100">
+ <course>149.049561</course>
+ <speed>0.063043</speed>
+ <name>WP0016</name>
+</trkpt>
+<trkpt lat="54.786899100" lon="-2.344349500">
+ <course>161.409058</course>
+ <speed>0.057025</speed>
+ <name>WP0017</name>
+</trkpt>
+<trkpt lat="54.786896800" lon="-2.344349800">
+ <course>175.698807</course>
+ <speed>0.050291</speed>
+ <name>WP0018</name>
+</trkpt>
+<trkpt lat="54.786894700" lon="-2.344350500">
+ <course>169.120071</course>
+ <speed>0.050291</speed>
+ <name>WP0019</name>
+</trkpt>
+<trkpt lat="54.786893000" lon="-2.344352300">
+ <course>148.594345</course>
+ <speed>0.046561</speed>
+ <name>WP0020</name>
+</trkpt>
+<trkpt lat="54.786891400" lon="-2.344354300">
+ <course>144.216919</course>
+ <speed>0.042504</speed>
+ <name>WP0021</name>
+</trkpt>
+<trkpt lat="54.786889700" lon="-2.344355900">
+ <course>151.511292</course>
+ <speed>0.046561</speed>
+ <name>WP0022</name>
+</trkpt>
+<trkpt lat="54.786888400" lon="-2.344356700">
+ <course>160.463150</course>
+ <speed>0.026882</speed>
+ <name>WP0023</name>
+</trkpt>
+<trkpt lat="54.786887400" lon="-2.344356700">
+ <course>180.000000</course>
+ <speed>0.019008</speed>
+ <name>WP0024</name>
+</trkpt>
+<trkpt lat="54.786886600" lon="-2.344357000">
+ <course>167.798660</course>
+ <speed>0.000000</speed>
+ <name>WP0025</name>
+</trkpt>
+<trkpt lat="54.786886000" lon="-2.344357200">
+ <course>169.120071</course>
+ <speed>0.000000</speed>
+ <name>WP0026</name>
+</trkpt>
+<trkpt lat="54.786885400" lon="-2.344357400">
+ <course>169.120071</course>
+ <speed>0.000000</speed>
+ <name>WP0027</name>
+</trkpt>
+<trkpt lat="54.786884900" lon="-2.344356900">
+ <speed>0.000000</speed>
+ <name>WP0028</name>
+</trkpt>
+<trkpt lat="54.786884800" lon="-2.344356300">
+ <speed>0.000000</speed>
+ <name>WP0029</name>
+</trkpt>
+<trkpt lat="54.786877300" lon="-2.344355400">
+ <speed>0.167877</speed>
+ <name>WP0030</name>
+</trkpt>
+<trkpt lat="54.786875900" lon="-2.344370000">
+ <course>99.441742</course>
+ <speed>0.190083</speed>
+ <name>WP0031</name>
+</trkpt>
+<trkpt lat="54.786883500" lon="-2.344370000">
+ <course>0.000000</course>
+ <speed>0.170016</speed>
+ <name>WP0032</name>
+</trkpt>
+<trkpt lat="54.786881400" lon="-2.344368600">
+ <speed>0.053764</speed>
+ <name>WP0033</name>
+</trkpt>
+<trkpt lat="54.786878700" lon="-2.344367600">
+ <speed>0.063043</speed>
+ <name>WP0034</name>
+</trkpt>
+<trkpt lat="54.786876400" lon="-2.344365300">
+ <speed>0.057025</speed>
+ <name>WP0035</name>
+</trkpt>
+<trkpt lat="54.786877400" lon="-2.344361000">
+ <speed>0.057025</speed>
+ <name>WP0036</name>
+</trkpt>
+<trkpt lat="54.786939600" lon="-2.344332500">
+ <speed>1.432199</speed>
+ <name>WP0037</name>
+</trkpt>
+<trkpt lat="54.787010100" lon="-2.344387100">
+ <course>24.064192</course>
+ <speed>1.432560</speed>
+ <name>WP0038</name>
+</trkpt>
+<trkpt lat="54.787079800" lon="-2.344423000">
+ <course>16.541142</course>
+ <speed>1.618836</speed>
+ <name>WP0039</name>
+</trkpt>
+<trkpt lat="54.787159200" lon="-2.344461600">
+ <course>15.659211</course>
+ <speed>1.835854</speed>
+ <name>WP0040</name>
+</trkpt>
+<trkpt lat="54.787268800" lon="-2.344447800">
+ <speed>2.446469</speed>
+ <name>WP0041</name>
+</trkpt>
+<trkpt lat="54.787316800" lon="-2.344428600">
+ <speed>1.096733</speed>
+ <name>WP0042</name>
+</trkpt>
+<trkpt lat="54.787358600" lon="-2.344494600">
+ <course>42.315998</course>
+ <speed>1.258575</speed>
+ <name>WP0043</name>
+</trkpt>
+<trkpt lat="54.787398000" lon="-2.344587300">
+ <course>53.605648</course>
+ <speed>1.478501</speed>
+ <name>WP0044</name>
+</trkpt>
+<trkpt lat="54.787446000" lon="-2.344635900">
+ <course>30.277189</course>
+ <speed>1.237587</speed>
+ <name>WP0045</name>
+</trkpt>
+<trkpt lat="54.787489200" lon="-2.344701500">
+ <course>41.205185</course>
+ <speed>1.278231</speed>
+ <name>WP0046</name>
+</trkpt>
+<trkpt lat="54.787536100" lon="-2.344777300">
+ <course>42.981739</course>
+ <speed>1.427271</speed>
+ <name>WP0047</name>
+</trkpt>
+<trkpt lat="54.787576800" lon="-2.344848600">
+ <course>45.288700</course>
+ <speed>1.287806</speed>
+ <name>WP0048</name>
+</trkpt>
+<trkpt lat="54.787619000" lon="-2.344905600">
+ <course>37.912586</course>
+ <speed>1.190717</speed>
+ <name>WP0049</name>
+</trkpt>
+<trkpt lat="54.787654600" lon="-2.344976100">
+ <course>48.789742</course>
+ <speed>1.202943</speed>
+ <name>WP0050</name>
+</trkpt>
+<trkpt lat="54.787706000" lon="-2.345057400">
+ <course>42.365654</course>
+ <speed>1.548800</speed>
+ <name>WP0051</name>
+</trkpt>
+<trkpt lat="54.787704600" lon="-2.345093500">
+ <course>93.847755</course>
+ <speed>0.464052</speed>
+ <name>WP0052</name>
+</trkpt>
+<trkpt lat="54.787650000" lon="-2.345038300">
+ <speed>1.407002</speed>
+ <name>WP0053</name>
+</trkpt>
+<trkpt lat="54.787599300" lon="-2.344979500">
+ <speed>1.357865</speed>
+ <name>WP0054</name>
+</trkpt>
+<trkpt lat="54.787556600" lon="-2.344911400">
+ <speed>1.291588</speed>
+ <name>WP0055</name>
+</trkpt>
+<trkpt lat="54.787516700" lon="-2.344837400">
+ <speed>1.300648</speed>
+ <name>WP0056</name>
+</trkpt>
+<trkpt lat="54.787474300" lon="-2.344746700">
+ <speed>1.499009</speed>
+ <name>WP0057</name>
+</trkpt>
+<trkpt lat="54.787424700" lon="-2.344667700">
+ <speed>1.499370</speed>
+ <name>WP0058</name>
+</trkpt>
+<trkpt lat="54.787376900" lon="-2.344594500">
+ <speed>1.419783</speed>
+ <name>WP0059</name>
+</trkpt>
+<trkpt lat="54.787337800" lon="-2.344539200">
+ <speed>1.123262</speed>
+ <name>WP0060</name>
+</trkpt>
+<trkpt lat="54.787292000" lon="-2.344480900">
+ <speed>1.264875</speed>
+ <name>WP0061</name>
+</trkpt>
+<trkpt lat="54.787233600" lon="-2.344424200">
+ <speed>1.489943</speed>
+ <name>WP0062</name>
+</trkpt>
+<trkpt lat="54.787188100" lon="-2.344418700">
+ <speed>1.015479</speed>
+ <name>WP0063</name>
+</trkpt>
+<trkpt lat="54.787137900" lon="-2.344400400">
+ <speed>1.142083</speed>
+ <name>WP0064</name>
+</trkpt>
+<trkpt lat="54.787093100" lon="-2.344371800">
+ <speed>1.062938</speed>
+ <name>WP0065</name>
+</trkpt>
+<trkpt lat="54.787020700" lon="-2.344353100">
+ <speed>1.629736</speed>
+ <name>WP0066</name>
+</trkpt>
+<trkpt lat="54.786968300" lon="-2.344298000">
+ <speed>1.364369</speed>
+ <name>WP0067</name>
+</trkpt>
+<trkpt lat="54.786953700" lon="-2.344270600">
+ <speed>0.478995</speed>
+ <name>WP0068</name>
+</trkpt>
+<trkpt lat="54.786928100" lon="-2.344276200">
+ <course>172.810944</course>
+ <speed>0.574354</speed>
+ <name>WP0069</name>
+</trkpt>
+<trkpt lat="54.786947500" lon="-2.344239500">
+ <speed>0.638974</speed>
+ <name>WP0070</name>
+</trkpt>
+<trkpt lat="54.786874000" lon="-2.344211000">
+ <speed>1.676724</speed>
+ <name>WP0071</name>
+</trkpt>
+<trkpt lat="54.786889500" lon="-2.344175300">
+ <speed>0.573724</speed>
+ <name>WP0072</name>
+</trkpt>
+<trkpt lat="54.786905700" lon="-2.344154600">
+ <speed>0.448210</speed>
+ <name>WP0073</name>
+</trkpt>
+<trkpt lat="54.786887300" lon="-2.344152700">
+ <speed>0.410333</speed>
+ <name>WP0074</name>
+</trkpt>
+<trkpt lat="54.786967100" lon="-2.344200300">
+ <course>18.980536</course>
+ <speed>1.878750</speed>
+ <name>WP0075</name>
+</trkpt>
+<trkpt lat="54.786950400" lon="-2.344192500">
+ <speed>0.384889</speed>
+ <name>WP0076</name>
+</trkpt>
+<trkpt lat="54.786550600" lon="-2.344644800">
+ <course>146.881775</course>
+ <speed>10.627611</speed>
+ <name>WP0077</name>
+</trkpt>
+<trkpt lat="54.786423800" lon="-2.344905900">
+ <course>130.104218</course>
+ <speed>4.382399</speed>
+ <name>WP0078</name>
+</trkpt>
+<trkpt lat="54.786339400" lon="-2.344960500">
+ <course>159.542908</course>
+ <speed>2.005446</speed>
+ <name>WP0079</name>
+</trkpt>
+<trkpt lat="54.786129600" lon="-2.345095800">
+ <course>159.601395</course>
+ <speed>4.983410</speed>
+ <name>WP0080</name>
+</trkpt>
+<trkpt lat="54.786113000" lon="-2.345044900">
+ <speed>0.750528</speed>
+ <name>WP0081</name>
+</trkpt>
+<trkpt lat="54.786210000" lon="-2.344944400">
+ <speed>2.515643</speed>
+ <name>WP0082</name>
+</trkpt>
+<trkpt lat="54.786279400" lon="-2.344882300">
+ <speed>1.738717</speed>
+ <name>WP0083</name>
+</trkpt>
+<trkpt lat="54.786328600" lon="-2.344835700">
+ <speed>1.248053</speed>
+ <name>WP0084</name>
+</trkpt>
+<trkpt lat="54.786377000" lon="-2.344791200">
+ <speed>1.219648</speed>
+ <name>WP0085</name>
+</trkpt>
+<trkpt lat="54.786418000" lon="-2.344751600">
+ <speed>1.044767</speed>
+ <name>WP0086</name>
+</trkpt>
+<trkpt lat="54.786450500" lon="-2.344721800">
+ <speed>0.818463</speed>
+ <name>WP0087</name>
+</trkpt>
+<trkpt lat="54.786480100" lon="-2.344698000">
+ <speed>0.726058</speed>
+ <name>WP0088</name>
+</trkpt>
+<trkpt lat="54.786506500" lon="-2.344674100">
+ <speed>0.552369</speed>
+ <name>WP0089</name>
+</trkpt>
+<trkpt lat="54.786529400" lon="-2.344655300">
+ <speed>0.563878</speed>
+ <name>WP0090</name>
+</trkpt>
+<trkpt lat="54.786550300" lon="-2.344636900">
+ <speed>0.521951</speed>
+ <name>WP0091</name>
+</trkpt>
+<trkpt lat="54.786568700" lon="-2.344621400">
+ <speed>0.455804</speed>
+ <name>WP0092</name>
+</trkpt>
+<trkpt lat="54.786586200" lon="-2.344606000">
+ <speed>0.436778</speed>
+ <name>WP0093</name>
+</trkpt>
+<trkpt lat="54.786601800" lon="-2.344590800">
+ <speed>0.398269</speed>
+ <name>WP0094</name>
+</trkpt>
+<trkpt lat="54.786616000" lon="-2.344576900">
+ <speed>0.363154</speed>
+ <name>WP0095</name>
+</trkpt>
+<trkpt lat="54.786630100" lon="-2.344563400">
+ <speed>0.358144</speed>
+ <name>WP0096</name>
+</trkpt>
+<trkpt lat="54.786643500" lon="-2.344550500">
+ <speed>0.341092</speed>
+ <name>WP0097</name>
+</trkpt>
+<trkpt lat="54.786656400" lon="-2.344538400">
+ <speed>0.326479</speed>
+ <name>WP0098</name>
+</trkpt>
+<trkpt lat="54.786712800" lon="-2.344309700">
+ <speed>3.193230</speed>
+ <name>WP0099</name>
+</trkpt>
+<trkpt lat="54.786421700" lon="-2.344238300">
+ <speed>6.545493</speed>
+ <name>WP0100</name>
+</trkpt>
+<trkpt lat="54.786106300" lon="-2.344361100">
+ <course>167.346375</course>
+ <speed>7.196805</speed>
+ <name>WP0101</name>
+</trkpt>
+<trkpt lat="54.785876000" lon="-2.344429400">
+ <course>170.295609</course>
+ <speed>5.201792</speed>
+ <name>WP0102</name>
+</trkpt>
+<trkpt lat="54.785637300" lon="-2.344343800">
+ <speed>5.426836</speed>
+ <name>WP0103</name>
+</trkpt>
+<trkpt lat="54.785565000" lon="-2.344340400">
+ <speed>1.610220</speed>
+ <name>WP0104</name>
+</trkpt>
+<trkpt lat="54.785501100" lon="-2.344222400">
+ <speed>2.078176</speed>
+ <name>WP0105</name>
+</trkpt>
+<trkpt lat="54.785521000" lon="-2.344218800">
+ <speed>0.445379</speed>
+ <name>WP0106</name>
+</trkpt>
+<trkpt lat="54.785462300" lon="-2.344312400">
+ <course>137.402069</course>
+ <speed>1.775321</speed>
+ <name>WP0107</name>
+</trkpt>
+<trkpt lat="54.785276400" lon="-2.344252900">
+ <speed>4.208789</speed>
+ <name>WP0108</name>
+</trkpt>
+<trkpt lat="54.785179600" lon="-2.344116300">
+ <speed>2.778599</speed>
+ <name>WP0109</name>
+</trkpt>
+<trkpt lat="54.785117200" lon="-2.344006700">
+ <speed>1.977414</speed>
+ <name>WP0110</name>
+</trkpt>
+<trkpt lat="54.785218000" lon="-2.344177300">
+ <course>44.302502</course>
+ <speed>2.613213</speed>
+ <name>WP0111</name>
+</trkpt>
+<trkpt lat="54.785293900" lon="-2.344022300">
+ <speed>2.175488</speed>
+ <name>WP0112</name>
+</trkpt>
+<trkpt lat="54.785521400" lon="-2.344255100">
+ <course>30.543665</course>
+ <speed>5.881074</speed>
+ <name>WP0113</name>
+</trkpt>
+<trkpt lat="54.785671200" lon="-2.344188200">
+ <speed>3.443919</speed>
+ <name>WP0114</name>
+</trkpt>
+<trkpt lat="54.785927500" lon="-2.344016000">
+ <speed>6.119472</speed>
+ <name>WP0115</name>
+</trkpt>
+<trkpt lat="54.786170000" lon="-2.344095900">
+ <course>10.757442</course>
+ <speed>5.495544</speed>
+ <name>WP0116</name>
+</trkpt>
+<trkpt lat="54.786300400" lon="-2.344209100">
+ <course>26.591137</course>
+ <speed>3.246643</speed>
+ <name>WP0117</name>
+</trkpt>
+<trkpt lat="54.786436200" lon="-2.344380400">
+ <course>36.030758</course>
+ <speed>3.738654</speed>
+ <name>WP0118</name>
+</trkpt>
+<trkpt lat="54.786480200" lon="-2.344508600">
+ <course>59.238380</course>
+ <speed>1.915319</speed>
+ <name>WP0119</name>
+</trkpt>
+<trkpt lat="54.786509900" lon="-2.344486200">
+ <speed>0.720814</speed>
+ <name>WP0120</name>
+</trkpt>
+<trkpt lat="54.786535000" lon="-2.344489800">
+ <course>4.727779</course>
+ <speed>0.560343</speed>
+ <name>WP0121</name>
+</trkpt>
+<trkpt lat="54.786657100" lon="-2.344486000">
+ <speed>2.718789</speed>
+ <name>WP0122</name>
+</trkpt>
+<trkpt lat="54.786667100" lon="-2.344606900">
+ <course>81.836906</course>
+ <speed>1.306607</speed>
+ <name>WP0123</name>
+</trkpt>
+<trkpt lat="54.786687600" lon="-2.344578700">
+ <speed>0.582474</speed>
+ <name>WP0124</name>
+</trkpt>
+<trkpt lat="54.786707600" lon="-2.344565300">
+ <speed>0.477105</speed>
+ <name>WP0125</name>
+</trkpt>
+<trkpt lat="54.786715700" lon="-2.344577800">
+ <course>41.664234</course>
+ <speed>0.241189</speed>
+ <name>WP0126</name>
+</trkpt>
+<trkpt lat="54.786721300" lon="-2.344563900">
+ <speed>0.217560</speed>
+ <name>WP0127</name>
+</trkpt>
+<trkpt lat="54.786725800" lon="-2.344570900">
+ <course>41.891056</course>
+ <speed>0.133058</speed>
+ <name>WP0128</name>
+</trkpt>
+<trkpt lat="54.786755500" lon="-2.344623600">
+ <course>45.655930</course>
+ <speed>0.945843</speed>
+ <name>WP0129</name>
+</trkpt>
+<trkpt lat="54.786780200" lon="-2.344553000">
+ <speed>1.060215</speed>
+ <name>WP0130</name>
+</trkpt>
+<trkpt lat="54.786783900" lon="-2.344515800">
+ <speed>0.484619</speed>
+ <name>WP0131</name>
+</trkpt>
+<trkpt lat="54.786801900" lon="-2.344472200">
+ <speed>0.688249</speed>
+ <name>WP0132</name>
+</trkpt>
+<trkpt lat="54.786801800" lon="-2.344466100">
+ <speed>0.076033</speed>
+ <name>WP0133</name>
+</trkpt>
+<trkpt lat="54.786801300" lon="-2.344469800">
+ <course>103.189636</course>
+ <speed>0.046561</speed>
+ <name>WP0134</name>
+</trkpt>
+<trkpt lat="54.786803700" lon="-2.344463600">
+ <speed>0.096924</speed>
+ <name>WP0135</name>
+</trkpt>
+<trkpt lat="54.786806400" lon="-2.344457400">
+ <speed>0.098770</speed>
+ <name>WP0136</name>
+</trkpt>
+<trkpt lat="54.786808300" lon="-2.344454200">
+ <speed>0.057025</speed>
+ <name>WP0137</name>
+</trkpt>
+<trkpt lat="54.786809100" lon="-2.344457100">
+ <course>64.432991</course>
+ <speed>0.032923</speed>
+ <name>WP0138</name>
+</trkpt>
+<trkpt lat="54.786811800" lon="-2.344452300">
+ <speed>0.085008</speed>
+ <name>WP0139</name>
+</trkpt>
+<trkpt lat="54.786815500" lon="-2.344450300">
+ <speed>0.087107</speed>
+ <name>WP0140</name>
+</trkpt>
+<trkpt lat="54.786818200" lon="-2.344449000">
+ <speed>0.063043</speed>
+ <name>WP0141</name>
+</trkpt>
+<trkpt lat="54.786820300" lon="-2.344445100">
+ <speed>0.065847</speed>
+ <name>WP0142</name>
+</trkpt>
+<trkpt lat="54.786850700" lon="-2.344378700">
+ <speed>1.088465</speed>
+ <name>WP0143</name>
+</trkpt>
+<trkpt lat="54.786851100" lon="-2.344379500">
+ <course>49.070705</course>
+ <speed>0.000000</speed>
+ <name>WP0144</name>
+</trkpt>
+<trkpt lat="54.786851700" lon="-2.344372600">
+ <speed>0.091161</speed>
+ <name>WP0145</name>
+</trkpt>
+<trkpt lat="54.786850500" lon="-2.344371500">
+ <speed>0.038017</speed>
+ <name>WP0146</name>
+</trkpt>
+<trkpt lat="54.786851700" lon="-2.344361900">
+ <speed>0.127512</speed>
+ <name>WP0147</name>
+</trkpt>
+<trkpt lat="54.786852200" lon="-2.344355400">
+ <speed>0.085008</speed>
+ <name>WP0148</name>
+</trkpt>
+<trkpt lat="54.786855700" lon="-2.344344300">
+ <speed>0.162407</speed>
+ <name>WP0149</name>
+</trkpt>
+<trkpt lat="54.786856800" lon="-2.344342000">
+ <speed>0.038017</speed>
+ <name>WP0150</name>
+</trkpt>
+<trkpt lat="54.786854800" lon="-2.344344100">
+ <course>148.807159</course>
+ <speed>0.050291</speed>
+ <name>WP0151</name>
+</trkpt>
+<trkpt lat="54.786854300" lon="-2.344339000">
+ <speed>0.068536</speed>
+ <name>WP0152</name>
+</trkpt>
+<trkpt lat="54.786854300" lon="-2.344334100">
+ <speed>0.063043</speed>
+ <name>WP0153</name>
+</trkpt>
+<trkpt lat="54.786852500" lon="-2.344335600">
+ <course>154.334946</course>
+ <speed>0.046561</speed>
+ <name>WP0154</name>
+</trkpt>
+<trkpt lat="54.786852100" lon="-2.344330900">
+ <speed>0.060110</speed>
+ <name>WP0155</name>
+</trkpt>
+<trkpt lat="54.786854400" lon="-2.344318100">
+ <speed>0.172128</speed>
+ <name>WP0156</name>
+</trkpt>
+<trkpt lat="54.786856800" lon="-2.344306700">
+ <speed>0.155590</speed>
+ <name>WP0157</name>
+</trkpt>
+<trkpt lat="54.786858400" lon="-2.344299800">
+ <speed>0.093121</speed>
+ <name>WP0158</name>
+</trkpt>
+<trkpt lat="54.786858200" lon="-2.344299800">
+ <course>180.000000</course>
+ <speed>0.000000</speed>
+ <name>WP0159</name>
+</trkpt>
+<trkpt lat="54.786857500" lon="-2.344300600">
+ <course>146.615356</course>
+ <speed>0.019008</speed>
+ <name>WP0160</name>
+</trkpt>
+<trkpt lat="54.786856000" lon="-2.344304100">
+ <course>126.621498</course>
+ <speed>0.060110</speed>
+ <name>WP0161</name>
+</trkpt>
+<trkpt lat="54.786854600" lon="-2.344307000">
+ <course>129.936798</course>
+ <speed>0.046561</speed>
+ <name>WP0162</name>
+</trkpt>
+<trkpt lat="54.786853500" lon="-2.344309200">
+ <course>130.929291</course>
+ <speed>0.032923</speed>
+ <name>WP0163</name>
+</trkpt>
+<trkpt lat="54.786852700" lon="-2.344310700">
+ <course>132.766678</course>
+ <speed>0.000000</speed>
+ <name>WP0164</name>
+</trkpt>
+<trkpt lat="54.786851700" lon="-2.344313200">
+ <course>124.748962</course>
+ <speed>0.038017</speed>
+ <name>WP0165</name>
+</trkpt>
+<trkpt lat="54.786851100" lon="-2.344314400">
+ <course>130.929291</course>
+ <speed>0.026882</speed>
+ <name>WP0166</name>
+</trkpt>
+<trkpt lat="54.786850500" lon="-2.344316200">
+ <course>120.031418</course>
+ <speed>0.026882</speed>
+ <name>WP0167</name>
+</trkpt>
+<trkpt lat="54.786848600" lon="-2.344321700">
+ <course>120.925941</course>
+ <speed>0.082855</speed>
+ <name>WP0168</name>
+</trkpt>
+<trkpt lat="54.786846900" lon="-2.344326700">
+ <course>120.525436</course>
+ <speed>0.073619</speed>
+ <name>WP0169</name>
+</trkpt>
+<trkpt lat="54.786845300" lon="-2.344330700">
+ <course>124.748962</course>
+ <speed>0.063043</speed>
+ <name>WP0170</name>
+</trkpt>
+<trkpt lat="54.786843800" lon="-2.344334000">
+ <course>128.248459</course>
+ <speed>0.053764</speed>
+ <name>WP0171</name>
+</trkpt>
+<trkpt lat="54.786842400" lon="-2.344336100">
+ <course>139.142487</course>
+ <speed>0.038017</speed>
+ <name>WP0172</name>
+</trkpt>
+<trkpt lat="54.786841200" lon="-2.344337700">
+ <course>142.445953</course>
+ <speed>0.032923</speed>
+ <name>WP0173</name>
+</trkpt>
+<trkpt lat="54.786840300" lon="-2.344339500">
+ <course>130.929291</course>
+ <speed>0.026882</speed>
+ <name>WP0174</name>
+</trkpt>
+<trkpt lat="54.786840200" lon="-2.344340700">
+ <course>98.223473</course>
+ <speed>0.019008</speed>
+ <name>WP0175</name>
+</trkpt>
+<trkpt lat="54.786840400" lon="-2.344342600">
+ <course>79.654457</course>
+ <speed>0.019008</speed>
+ <name>WP0176</name>
+</trkpt>
+<trkpt lat="54.786840000" lon="-2.344345200">
+ <course>104.938911</course>
+ <speed>0.026882</speed>
+ <name>WP0177</name>
+</trkpt>
+<trkpt lat="54.786839700" lon="-2.344347800">
+ <course>101.315720</course>
+ <speed>0.019008</speed>
+ <name>WP0178</name>
+</trkpt>
+<trkpt lat="54.786839900" lon="-2.344349600">
+ <course>79.093140</course>
+ <speed>0.019008</speed>
+ <name>WP0179</name>
+</trkpt>
+<trkpt lat="54.786839900" lon="-2.344350700">
+ <course>90.000000</course>
+ <speed>0.019008</speed>
+ <name>WP0180</name>
+</trkpt>
+<trkpt lat="54.786840200" lon="-2.344350700">
+ <course>0.000000</course>
+ <speed>0.000000</speed>
+ <name>WP0181</name>
+</trkpt>
+<trkpt lat="54.786840900" lon="-2.344350000">
+ <speed>0.019008</speed>
+ <name>WP0182</name>
+</trkpt>
+<trkpt lat="54.786842300" lon="-2.344348300">
+ <speed>0.038017</speed>
+ <name>WP0183</name>
+</trkpt>
+<trkpt lat="54.786844000" lon="-2.344346000">
+ <speed>0.046561</speed>
+ <name>WP0184</name>
+</trkpt>
+<trkpt lat="54.786845900" lon="-2.344344300">
+ <speed>0.050291</speed>
+ <name>WP0185</name>
+</trkpt>
+<trkpt lat="54.786847900" lon="-2.344343000">
+ <speed>0.050291</speed>
+ <name>WP0186</name>
+</trkpt>
+<trkpt lat="54.786849500" lon="-2.344343100">
+ <course>2.063974</course>
+ <speed>0.032923</speed>
+ <name>WP0187</name>
+</trkpt>
+<trkpt lat="54.786850000" lon="-2.344344700">
+ <course>61.544453</course>
+ <speed>0.019008</speed>
+ <name>WP0188</name>
+</trkpt>
+<trkpt lat="54.786850500" lon="-2.344345600">
+ <course>46.065872</course>
+ <speed>0.019008</speed>
+ <name>WP0189</name>
+</trkpt>
+<trkpt lat="54.786851100" lon="-2.344345900">
+ <course>16.082796</course>
+ <speed>0.019008</speed>
+ <name>WP0190</name>
+</trkpt>
+<trkpt lat="54.786851900" lon="-2.344345400">
+ <speed>0.000000</speed>
+ <name>WP0191</name>
+</trkpt>
+<trkpt lat="54.786852700" lon="-2.344344700">
+ <speed>0.000000</speed>
+ <name>WP0192</name>
+</trkpt>
+<trkpt lat="54.786853500" lon="-2.344343600">
+ <speed>0.000000</speed>
+ <name>WP0193</name>
+</trkpt>
+<trkpt lat="54.786854300" lon="-2.344342300">
+ <speed>0.019008</speed>
+ <name>WP0194</name>
+</trkpt>
+<trkpt lat="54.786855100" lon="-2.344340600">
+ <speed>0.026882</speed>
+ <name>WP0195</name>
+</trkpt>
+<trkpt lat="54.786856200" lon="-2.344338400">
+ <speed>0.038017</speed>
+ <name>WP0196</name>
+</trkpt>
+<trkpt lat="54.786857000" lon="-2.344336600">
+ <speed>0.026882</speed>
+ <name>WP0197</name>
+</trkpt>
+<trkpt lat="54.786858200" lon="-2.344334500">
+ <speed>0.038017</speed>
+ <name>WP0198</name>
+</trkpt>
+<trkpt lat="54.786859900" lon="-2.344332700">
+ <speed>0.042504</speed>
+ <name>WP0199</name>
+</trkpt>
+<trkpt lat="54.786862100" lon="-2.344330500">
+ <speed>0.053764</speed>
+ <name>WP0200</name>
+</trkpt>
+<trkpt lat="54.786864100" lon="-2.344328100">
+ <speed>0.053764</speed>
+ <name>WP0201</name>
+</trkpt>
+<trkpt lat="54.787010400" lon="-2.344104300">
+ <speed>4.343226</speed>
+ <name>WP0202</name>
+</trkpt>
+<trkpt lat="54.787229300" lon="-2.343736200">
+ <speed>6.788423</speed>
+ <name>WP0203</name>
+</trkpt>
+<trkpt lat="54.787421800" lon="-2.343407600">
+ <speed>6.013606</speed>
+ <name>WP0204</name>
+</trkpt>
+<trkpt lat="54.787607100" lon="-2.343151200">
+ <speed>5.277713</speed>
+ <name>WP0205</name>
+</trkpt>
+<trkpt lat="54.787730000" lon="-2.342980300">
+ <speed>3.507230</speed>
+ <name>WP0206</name>
+</trkpt>
+<trkpt lat="54.787984800" lon="-2.342500800">
+ <speed>8.370941</speed>
+ <name>WP0207</name>
+</trkpt>
+<trkpt lat="54.787651300" lon="-2.342851000">
+ <course>148.805801</course>
+ <speed>8.679982</speed>
+ <name>WP0208</name>
+</trkpt>
+<trkpt lat="54.787296200" lon="-2.343383500">
+ <course>139.150696</course>
+ <speed>10.451539</speed>
+ <name>WP0209</name>
+</trkpt>
+<trkpt lat="54.787039700" lon="-2.343788000">
+ <course>137.718918</course>
+ <speed>7.718669</speed>
+ <name>WP0210</name>
+</trkpt>
+<trkpt lat="54.786803800" lon="-2.344073800">
+ <course>145.062073</course>
+ <speed>6.406710</speed>
+ <name>WP0211</name>
+</trkpt>
+<trkpt lat="54.786802300" lon="-2.344003800">
+ <speed>0.899237</speed>
+ <name>WP0212</name>
+</trkpt>
+<trkpt lat="54.786616200" lon="-2.344166600">
+ <course>153.232285</course>
+ <speed>4.640603</speed>
+ <name>WP0213</name>
+</trkpt>
+<trkpt lat="54.786540500" lon="-2.344416600">
+ <course>117.705025</course>
+ <speed>3.625063</speed>
+ <name>WP0214</name>
+</trkpt>
+<trkpt lat="54.786501700" lon="-2.344660800">
+ <course>105.405190</course>
+ <speed>3.251814</speed>
+ <name>WP0215</name>
+</trkpt>
+<trkpt lat="54.786513700" lon="-2.344705000">
+ <course>64.787437</course>
+ <speed>0.627275</speed>
+ <name>WP0216</name>
+</trkpt>
+<trkpt lat="54.786760100" lon="-2.344360500">
+ <speed>7.046580</speed>
+ <name>WP0217</name>
+</trkpt>
+<trkpt lat="54.787114900" lon="-2.343841500">
+ <speed>10.333961</speed>
+ <name>WP0218</name>
+</trkpt>
+<trkpt lat="54.786823000" lon="-2.344343500">
+ <course>135.240036</course>
+ <speed>9.152427</speed>
+ <name>WP0219</name>
+</trkpt>
+<trkpt lat="54.786727900" lon="-2.344510000">
+ <course>134.727890</course>
+ <speed>3.008605</speed>
+ <name>WP0220</name>
+</trkpt>
+<trkpt lat="54.786797300" lon="-2.344411700">
+ <speed>1.994969</speed>
+ <name>WP0221</name>
+</trkpt>
+<trkpt lat="54.786798000" lon="-2.344388300">
+ <speed>0.300548</speed>
+ <name>WP0222</name>
+</trkpt>
+<trkpt lat="54.787078000" lon="-2.343880200">
+ <speed>9.022692</speed>
+ <name>WP0223</name>
+</trkpt>
+<trkpt lat="54.787064400" lon="-2.343910000">
+ <course>128.360611</course>
+ <speed>0.487963</speed>
+ <name>WP0224</name>
+</trkpt>
+<trkpt lat="54.787059700" lon="-2.343934800">
+ <course>108.194084</course>
+ <speed>0.335216</speed>
+ <name>WP0225</name>
+</trkpt>
+<trkpt lat="54.787079300" lon="-2.343931200">
+ <speed>0.438841</speed>
+ <name>WP0226</name>
+</trkpt>
+<trkpt lat="54.787085100" lon="-2.343997400">
+ <course>81.360321</course>
+ <speed>0.859589</speed>
+ <name>WP0227</name>
+</trkpt>
+<trkpt lat="54.787090000" lon="-2.343998400">
+ <course>6.711519</course>
+ <speed>0.109195</speed>
+ <name>WP0228</name>
+</trkpt>
+<trkpt lat="54.787363500" lon="-2.343572600">
+ <speed>8.182794</speed>
+ <name>WP0229</name>
+</trkpt>
+<trkpt lat="54.787468300" lon="-2.343368600">
+ <speed>3.507539</speed>
+ <name>WP0230</name>
+</trkpt>
+<trkpt lat="54.787640700" lon="-2.343024900">
+ <speed>5.848113</speed>
+ <name>WP0231</name>
+</trkpt>
+<trkpt lat="54.787859200" lon="-2.342704200">
+ <speed>6.372952</speed>
+ <name>WP0232</name>
+</trkpt>
+<trkpt lat="54.787842200" lon="-2.342921800">
+ <course>97.715996</course>
+ <speed>2.818878</speed>
+ <name>WP0233</name>
+</trkpt>
+<trkpt lat="54.787355300" lon="-2.343799700">
+ <course>133.886002</course>
+ <speed>15.637352</speed>
+ <name>WP0234</name>
+</trkpt>
+<trkpt lat="54.787075000" lon="-2.344206800">
+ <course>140.055038</course>
+ <speed>8.139894</speed>
+ <name>WP0235</name>
+</trkpt>
+<trkpt lat="54.787010700" lon="-2.344363000">
+ <course>125.523293</course>
+ <speed>2.463761</speed>
+ <name>WP0236</name>
+</trkpt>
+<trkpt lat="54.786777100" lon="-2.344770400">
+ <course>134.839066</course>
+ <speed>7.375820</speed>
+ <name>WP0237</name>
+</trkpt>
+<trkpt lat="54.786630800" lon="-2.344906200">
+ <course>151.842575</course>
+ <speed>3.694468</speed>
+ <name>WP0238</name>
+</trkpt>
+<trkpt lat="54.786659200" lon="-2.344849700">
+ <speed>0.962317</speed>
+ <name>WP0239</name>
+</trkpt>
+<trkpt lat="54.786524100" lon="-2.345018400">
+ <course>144.244812</course>
+ <speed>3.706478</speed>
+ <name>WP0240</name>
+</trkpt>
+<trkpt lat="54.786864600" lon="-2.344376200">
+ <speed>11.200036</speed>
+ <name>WP0241</name>
+</trkpt>
+<trkpt lat="54.787250300" lon="-2.343633900">
+ <speed>12.827707</speed>
+ <name>WP0242</name>
+</trkpt>
+<trkpt lat="54.787807600" lon="-2.342578800">
+ <speed>18.368883</speed>
+ <name>WP0243</name>
+</trkpt>
+<trkpt lat="54.787178600" lon="-2.344040000">
+ <course>126.742546</course>
+ <speed>19.507580</speed>
+ <name>WP0244</name>
+</trkpt>
+<trkpt lat="54.786722100" lon="-2.344530500">
+ <course>148.218903</course>
+ <speed>7.472546</speed>
+ <name>WP0245</name>
+</trkpt>
+<trkpt lat="54.786872300" lon="-2.344456200">
+ <speed>2.483881</speed>
+ <name>WP0246</name>
+</trkpt>
+<trkpt lat="54.786790900" lon="-2.344473100">
+ <course>173.173264</course>
+ <speed>1.303782</speed>
+ <name>WP0247</name>
+</trkpt>
+<trkpt lat="54.786866200" lon="-2.344096600">
+ <speed>1.967664</speed>
+ <name>WP0248</name>
+</trkpt>
+<trkpt lat="54.786926000" lon="-2.344155900">
+ <course>29.760809</course>
+ <speed>1.533561</speed>
+ <name>WP0249</name>
+</trkpt>
+<trkpt lat="54.787223500" lon="-2.343181500">
+ <speed>14.154443</speed>
+ <name>WP0250</name>
+</trkpt>
+<trkpt lat="54.787151700" lon="-2.343740700">
+ <course>102.553291</course>
+ <speed>7.354651</speed>
+ <name>WP0251</name>
+</trkpt>
+<trkpt lat="54.787281000" lon="-2.343534000">
+ <speed>3.915116</speed>
+ <name>WP0252</name>
+</trkpt>
+<trkpt lat="54.787392100" lon="-2.343651100">
+ <course>31.289225</course>
+ <speed>2.894576</speed>
+ <name>WP0253</name>
+</trkpt>
+<trkpt lat="54.787738600" lon="-2.342950500">
+ <speed>11.849266</speed>
+ <name>WP0254</name>
+</trkpt>
+<trkpt lat="54.787550500" lon="-2.343047500">
+ <course>163.440262</course>
+ <speed>3.120760</speed>
+ <name>WP0255</name>
+</trkpt>
+<trkpt lat="54.786874100" lon="-2.344481700">
+ <course>129.279663</course>
+ <speed>2.973259</speed>
+ <name>WP0256</name>
+</trkpt>
+<trkpt lat="54.787425000" lon="-2.342911400">
+ <speed>23.597078</speed>
+ <name>WP0257</name>
+</trkpt>
+<trkpt lat="54.787020700" lon="-2.344089400">
+ <course>120.761200</course>
+ <speed>1.060176</speed>
+ <name>WP0258</name>
+</trkpt>
+<trkpt lat="54.787111400" lon="-2.344023100">
+ <speed>0.116564</speed>
+ <name>WP0259</name>
+</trkpt>
+</trkseg>
+</trk>
+</gpx>
${PNAME} -i gpx -f ${REFERENCE}/track/tracks.gpx -o gpssim -F ${TMPDIR}/tracks.gpssim
compare ${TMPDIR}/tracks.gpssim ${REFERENCE}/track
+#
+# WBT-200 tests
+#
+rm -f ${TMPDIR}/wbt-200.*
+${PNAME} -i wbt-bin -f ${REFERENCE}/wbt-200.bin -o gpx -F ${TMPDIR}/wbt-200.gpx
+# Remove the timestamp
+grep -v time <${TMPDIR}/wbt-200.gpx >${TMPDIR}/wbt-200.gpx2
+compare ${TMPDIR}/wbt-200.gpx2 ${REFERENCE}/wbt-200.gpx
exit 0
extern ff_vecs_t wfff_xml_vecs;
extern ff_vecs_t xcsv_vecs;
extern ff_vecs_t yahoo_vecs;
-extern ff_vecs_t wbt_vecs;
+extern ff_vecs_t wbt_svecs;
+extern ff_vecs_t wbt_fvecs;
static
vecs_t vec_list[] = {
NULL
},
{
- &wbt_vecs,
+ &wbt_svecs,
"wbt",
"Wintec WBT-100/200 GPS Download",
+ "bin"
+ },
+ {
+ &wbt_fvecs,
+ "wbt-bin",
+ "Wintec WBT-100/200 Binary file format",
NULL
},
{
*/
#include "defs.h"
-#include "jeeps/gpsserial.h"
+#include "gbser.h"
#include "grtcirc.h"
#include <errno.h>
+#define BAUD 9600
+#define TIMEOUT 1500
+
/*
A conversation looks like this
<< $PFST,NORMAL,*02
*/
-static gpsdevh *fd;
+/*static gpsdevh *fd;*/
+static void *fd;
+static FILE *fl;
static char *port;
static char *erase;
#define MYNAME "WBT-100/200"
-#define PRESTRKNAME "PRESALTTRK"
#define NL "\x0D\x0A"
+struct read_state {
+ route_head *route_head;
+ double plat, plon; /* previous point */
+ time_t ptim;
+ unsigned wpn;
+};
+
/* Number of lines to skip while waiting for an ACK from a command. I've seen
* conversations with up to 30 lines of cruft before the response so 50 isn't
* too crazy.
va_end(ap);
}
-/* Read a single character from the serial port. Kind of gross but we do
- * it like this so we can use Jeeps (which doesn't have an equivalent
- * function). Returns -1 if no char is available, -2 on error or the
- * retrieved char.
- */
-static int rd_char() {
- if (GPS_Serial_Chars_Ready(fd)) {
- unsigned char c;
- if (GPS_Serial_Read(fd, &c, 1) != 1) {
- return -2;
- } else {
- return c;
- }
- } else {
- return -1;
- }
-}
-
-/* Blocking version of above. It would be nicer to use select on the fd
- * rather than spinning in a loop here - but we're trying to stay platform
- * independent.
- */
-static int rd_char_b() {
- int c = rd_char();
- while (c == -1) {
- c = rd_char();
+static void rd_drain() {
+ if (gbser_flush(fd)) {
+ fatal(MYNAME ": Comm error\n");
}
-
- return c;
}
-/* Swallow any pending output from GPS */
-
-static int rd_drain() {
- int c = rd_char();
- while (c >= 0) {
- c = rd_char();
+static void rd_line(char *buf, int len) {
+ int rc;
+ if (rc = gbser_read_line(fd, buf, len, TIMEOUT, 0x0A, 0x0D), rc != gbser_OK) {
+ fatal(MYNAME ": Read error (%d)\n", rc);
}
-
- return c == -1 ? 0 : c;
}
-/* Read a line (up to 0x0A). Carriage returns are filtered out. Always tries to
- * read an entire line but discards any characters beyond len (because we're
- * only ever interested in fairly short lines.
- *
- * Returns the number of characters read or -2 on error. The buffer will contain
- * the (possibly truncated) string without any line terminator characters. The
- * buffer will always be null terminated.
- */
-static int rd_line(char *buf, int len) {
- int c, pos = 0, nr = 0;
- c = rd_char_b();
- while (c >= 0 && c != 0x0A) {
- nr++;
- if (c != 0x0D && pos < len-1) {
- buf[pos++] = (unsigned char) c;
- }
- c = rd_char_b();
+static void wr_cmd(const char *cmd) {
+ int rc;
+ db(3, "Sending: %s\n", cmd);
+ if (rc = gbser_print(fd, cmd), gbser_OK != rc) {
+ fatal(MYNAME ": Write error (%d)\n", rc);
}
-
- buf[pos] = '\0';
-
- return c < 0 ? c : nr;
-}
-
-static int wr_cmd(const char *cmd) {
- return GPS_Serial_Write(fd, cmd, strlen(cmd));
}
static void rd_init(const char *fname) {
port = xstrdup(fname);
db(1, "Opening port...\n");
- if (!GPS_Serial_On(port, &fd)) {
- fatal(MYNAME ": Can't initialise port '%s'\n", port);
+ if ((fd = gbser_init(port), NULL == fd) ||
+ gbser_set_port(fd, BAUD, 8, 0, 1)) {
+ fatal(MYNAME ": Can't initialise port \"%s\"\n", port);
}
}
static void rd_deinit(void) {
db(1, "Closing port...\n");
- if (!GPS_Serial_Off(fd)) {
- fatal(MYNAME ": Can't shut down port '%s'\n", port);
+ gbser_deinit(fd);
+ fd = NULL;
+ xfree(port);
+}
+
+static void rd_buf(void *buf, int len) {
+ int rc;
+ if (rc = gbser_read_wait(fd, buf, len, TIMEOUT), rc < 0) {
+ fatal(MYNAME ": Read error (%d)\n", rc);
+ } else if (rc < len) {
+ fatal(MYNAME ": Read timout\n");
}
+}
- xfree(port);
+static void file_init(const char *fname) {
+ db(1, "Opening file...\n");
+ if (fl = fopen(fname, "rb"), NULL == fl) {
+ fatal(MYNAME ": Can't open file '%s'\n", fname);
+ }
+}
+
+static void file_deinit(void) {
+ db(1, "Closing file...\n");
+ fclose(fl);
}
static int starts_with(const char *buf, const char *pat) {
*/
static void do_cmd(const char *cmd, const char *expect, char *buf, int len) {
- int rc, try;
-
- if (rd_drain() < 0) {
- fatal(MYNAME ": Read error\n");
- }
+ int try;
+ rd_drain();
wr_cmd(cmd);
wr_cmd(NL);
* middle of an NMEA sentence when we start listening.
*/
for (try = 0; try < RETRIES; try++) {
- if (rc = rd_line(buf, len), rc < 0) {
- fatal(MYNAME ": Read error\n");
- }
+ rd_line(buf, len);
if (starts_with(buf, expect)) {
db(2, "Got: %s\n", buf);
return;
do_cmd(cmd, cmd, buf, len);
}
-static void rd_buf(void *buf, int len) {
- char *bp = buf;
+static void data_chunk(struct read_state *st, const void *buf) {
+ char wp_name[20];
+ gbuint32 tim;
+ double lat, lon;
+ struct tm t;
+ time_t rtim;
+ waypoint *wpt = NULL;
+ const char *bp = buf;
- while (len > 0) {
- int rc = GPS_Serial_Read(fd, bp, len);
- if (rc < 0) {
- fatal(MYNAME ": Read error\n");
- }
- len -= rc;
- bp += rc;
+ tim = le_read32(bp + 0);
+
+ lat = (double) ((gbint32) le_read32(bp + 4)) / 10000000;
+ lon = (double) ((gbint32) le_read32(bp + 8)) / 10000000;
+
+ t.tm_sec = ((tim >> 0) & 0x3F);
+ t.tm_min = ((tim >> 6) & 0x3F);
+ t.tm_hour = ((tim >> 12) & 0x1F);
+ t.tm_mday = ((tim >> 17) & 0x1F);
+ t.tm_mon = ((tim >> 22) & 0x0F) - 1;
+ t.tm_year = ((tim >> 26) & 0x3F) + 100;
+
+ rtim = mkgmtime(&t);
+
+ if (lat >= 100) {
+ /* Start new track */
+ lat -= 100;
+ st->route_head = NULL;
+ } else {
+ wpt = waypt_new();
+
+ wpt->latitude = lat;;
+ wpt->longitude = lon;
+ wpt->creation_time = rtim;
+ wpt->centiseconds = 0;
+
+ /* OK to reuse buffer now */
+ sprintf(wp_name, "WP%04d", ++st->wpn);
+ wpt->shortname = xstrdup(wp_name);
+
+ wpt->speed = radtometers(
+ gcdist(RAD(st->plat), RAD(st->plon),
+ RAD(lat), RAD(lon))) /
+ (rtim - st->ptim);
+ wpt->course = DEG(heading(RAD(st->plat), RAD(st->plon),
+ RAD(lat), RAD(lon)));
+ wpt->pdop = 0;
+ wpt->fix = fix_unknown;
+
+ if (NULL == st->route_head) {
+ db(1, "New Track\n");
+ st->route_head = route_head_alloc();
+ track_add_head(st->route_head);
+ }
+
+ track_add_wpt(st->route_head, wpt);
+ }
+
+ st->ptim = rtim;
+ st->plat = lat;
+ st->plon = lon;
+}
+
+static void file_read(void) {
+ char buf[12];
+ int rc;
+ struct read_state st;
+
+ st.route_head = NULL;
+ st.wpn = 0;
+
+ rc = fread(buf, sizeof(buf), 1, fl);
+ while (rc == 1) {
+ data_chunk(&st, buf);
+ rc = fread(buf, sizeof(buf), 1, fl);
}
}
* Actually, it's OK because rd_line can read arbitrarily
* long lines returning only the first N characters
*/
- char line_buf[100];
- int count, d;
- gbuint32 tim, ptim = 0;
- double lat, lon;
- double plat = 0, plon = 0; /* previous point */
- struct tm t;
- time_t rtim;
- route_head *route_head = NULL;
- waypoint *wpt = NULL;
+ char line_buf[100];
+ int count, d;
+ struct read_state st;
+
+ st.route_head = NULL;
+ st.wpn = 0;
do_simple("$PFST,FIRMWAREVERSION", line_buf, sizeof(line_buf));
do_simple("$PFST,NORMAL", line_buf, sizeof(line_buf));
if (count == 0x10000) {
count = 0;
}
+
db(1, "Reading %d data\n", count);
for (d = 0; d < count; d++) {
rd_buf(line_buf, 12); /* twelve byte record */
- tim = le_read32(line_buf + 0);
-
- lat = (double) ((gbint32) le_read32(line_buf + 4)) / 10000000;
- lon = (double) ((gbint32) le_read32(line_buf + 8)) / 10000000;
-
- t.tm_sec = ((tim >> 0) & 0x3F);
- t.tm_min = ((tim >> 6) & 0x3F);
- t.tm_hour = ((tim >> 12) & 0x1F);
- t.tm_mday = ((tim >> 17) & 0x1F);
- t.tm_mon = ((tim >> 22) & 0x0F) - 1;
- t.tm_year = ((tim >> 26) & 0x3F) + 100;
-
- rtim = mkgmtime(&t);
-
- if (lat >= 100) {
- /* Start new track */
- lat -= 100;
- route_head = NULL;
- } else {
- wpt = waypt_new();
-
- wpt->latitude = lat;;
- wpt->longitude = lon;
- wpt->creation_time = rtim;
- wpt->centiseconds = 0;
-
- /* OK to reuse buffer now */
- sprintf(line_buf, "WP%04d", d + 1);
- wpt->shortname = xstrdup(line_buf);
-
- wpt->speed = radtometers(
- gcdist(RAD(plat), RAD(plon),
- RAD(lat), RAD(lon))) /
- (rtim - ptim);
- wpt->course = DEG(heading(RAD(plat), RAD(plon),
- RAD(lat), RAD(lon)));
- wpt->pdop = 0;
- wpt->fix = fix_unknown;
- wpt->sat = 0;
-
- if (NULL == route_head) {
- db(1, "New Track\n");
- route_head = route_head_alloc();
- track_add_head(route_head);
- }
-
- track_add_wpt(route_head, wpt);
- }
-
- ptim = rtim;
- plat = lat;
- plon = lon;
+ data_chunk(&st, line_buf);
}
/* Erase data? */
}
-static arglist_t wbt_args[] = {
+static arglist_t wbt_sargs[] = {
{ "erase", &erase, "Erase device data after download",
"0", ARGTYPE_BOOL, ARG_NOMINMAX },
ARG_TERMINATOR
};
-ff_vecs_t wbt_vecs = {
+ff_vecs_t wbt_svecs = {
ff_type_serial,
{ ff_cap_none, ff_cap_read, ff_cap_none },
rd_init,
data_read,
NULL,
NULL,
- wbt_args,
+ wbt_sargs,
+ CET_CHARSET_UTF8, 1 /* master process: don't convert anything | CET-REVIEW */
+};
+
+static arglist_t wbt_fargs[] = {
+ ARG_TERMINATOR
+};
+
+ff_vecs_t wbt_fvecs = {
+ ff_type_file,
+ { ff_cap_none, ff_cap_read, ff_cap_none },
+ file_init,
+ NULL,
+ file_deinit,
+ NULL,
+ file_read,
+ NULL,
+ NULL,
+ wbt_fargs,
CET_CHARSET_UTF8, 1 /* master process: don't convert anything | CET-REVIEW */
};